Compare commits

..

612 Commits

Author SHA1 Message Date
Jean-Philippe Lang
918ec276f1 Fixed test failure (#15182).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12240 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-26 11:50:16 +00:00
Jean-Philippe Lang
ba083225b7 Return to section anchor after wiki section edit (#15182).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12239 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-26 09:03:08 +00:00
Jean-Philippe Lang
7f22cc6113 Upgrade CodeRay to 1.1.0 (#8253).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12238 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-26 08:55:50 +00:00
Jean-Philippe Lang
e162f87964 Replaces <option value=""></option> which is not HTML5 valid (#15191).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12237 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-26 08:08:45 +00:00
Jean-Philippe Lang
711982b7b3 Prevents duplicate element ids (#15191).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12236 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-26 07:17:02 +00:00
Jean-Philippe Lang
3578cf4d9a Replaced acronym with abbr tags (#15191).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12235 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-26 07:15:08 +00:00
Jean-Philippe Lang
ec5dbdb0bd Fixed: JS-error while using a global custom query w/ project filter in a project context (#15190).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12234 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-26 06:56:35 +00:00
Toshi MARUYAMA
41ade07171 Simplified Chinese translation updated (#15186)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12232 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-24 06:06:30 +00:00
Toshi MARUYAMA
3109ed9320 code format cleanup app/models/changeset.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12231 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-24 05:40:32 +00:00
Toshi MARUYAMA
16b94e126b code format cleanup app/models/issue.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12230 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-24 05:40:21 +00:00
Toshi MARUYAMA
0552655ff5 Simplified Chinese translation for 2.3-stable updated (#15185)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12229 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-24 05:40:08 +00:00
Jean-Philippe Lang
b48fcdaa97 Avoid a query if enabled_modules association is already loaded (#15058).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12228 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-20 16:04:04 +00:00
Jean-Philippe Lang
99bf8c95ab Fixed that issue nested set update is triggered even if parent is not changed (#15135).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12226 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-20 09:25:14 +00:00
Jean-Philippe Lang
13e381d31d Projects selection on custom field form (#15136).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12225 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-20 08:29:55 +00:00
Toshi MARUYAMA
4eea64d38f remove trailing white-spaces from test/unit/user_test.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12224 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-17 01:00:04 +00:00
Jean-Philippe Lang
3172359f97 Avoid N queries when displaying the issue list with custom fields.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12223 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-15 16:38:17 +00:00
Jean-Philippe Lang
758cc2f2e6 Fixed that WikiContent#next_version raises a comparison of Symbol with Arel::Table failed error (#14773).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12222 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-14 17:07:17 +00:00
Jean-Philippe Lang
699317e12e Adds some links for wiki history navigation.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12221 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-14 16:58:39 +00:00
Jean-Philippe Lang
5f747faa58 Fixed that viewing/editing a wiki page without WikiContent raises an error (#14986).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12220 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-13 11:19:47 +00:00
Jean-Philippe Lang
94e7df78ca Fixed that controller_issues_edit_before/after_save hooks have no controller context (#15044).
Patch by Jordan Hollinger.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12219 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-13 10:31:04 +00:00
Jean-Philippe Lang
58c69b8123 Fixed that redmine:migrate_from_mantis fails to migrate projects with all upper case name (#15050).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12218 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-13 10:07:34 +00:00
Jean-Philippe Lang
7bea176cdb Avoid lots of CustomField.find_by_id calls when displaying an issue history with custom fields (#15072).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12217 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-13 10:04:59 +00:00
Jean-Philippe Lang
60d6e16978 Fixed that non array commit_update_keywords raises an error (#7590).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12216 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-13 10:03:13 +00:00
Jean-Philippe Lang
b071a937b3 List custom fields fielters: multiple select filter wider (#15073).
Patch by Jérôme Bataille.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12215 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-13 08:42:32 +00:00
Jean-Philippe Lang
176ce78574 Fixed that the mail method should return a Mail::Message (#15113).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12210 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-13 07:58:33 +00:00
Jean-Philippe Lang
c6c0491ad8 Migrate settings according to r12208 (#7590).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12209 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-13 07:39:20 +00:00
Jean-Philippe Lang
b6cb7aa8e3 Ability to define commit keywords per tracker (#7590).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12208 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-13 07:37:49 +00:00
Toshi MARUYAMA
b8aa4da28a remove unneeded "require 'diff'" from WikiController (#15105)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12207 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-11 17:37:51 +00:00
Toshi MARUYAMA
461342dd2e add missing "require 'diff'" to Redmine::Helpers::Diff (#15105)
Contributed by Felix Bünemann.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12206 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-11 17:37:38 +00:00
Toshi MARUYAMA
e7bc6364e1 add unit test of Redmine::Helpers::Diff (#15105)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12205 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-11 17:37:25 +00:00
Toshi MARUYAMA
53d749eb79 remove trailing white space from test/unit/wiki_content_test.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12204 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-10 03:56:54 +00:00
Toshi MARUYAMA
a9892b5f0e fix typo in the Dutch "label_user_mail_option_all" translation (#15075)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12203 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-09 18:19:38 +00:00
Jean-Philippe Lang
cfc65d9397 NoMethodError when uploading a file without logger (#14977).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12202 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-05 11:37:57 +00:00
Jean-Philippe Lang
1b63553dd4 Rows may not be oredered as expected with ruby1.8 (#4911).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12201 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-05 10:58:33 +00:00
Jean-Philippe Lang
3f566d6042 Hide issue custom fields when disabling issue tracking on new project.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12200 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-05 10:45:43 +00:00
Jean-Philippe Lang
7b1b605ae8 Don't update issues nor log time when importing old changesets (#4823).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12199 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-05 10:33:03 +00:00
Jean-Philippe Lang
0444ecca3c Pass the commit keyword used to update the issue to the plugin hook.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12198 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-05 10:02:31 +00:00
Jean-Philippe Lang
a77b462a53 Support for multiple issue update keywords/rules in commit messages (#4911).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12197 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-05 09:41:11 +00:00
Toshi MARUYAMA
b59d109680 German translation updated by Daniel Felix (#15028)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12196 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-02 13:31:19 +00:00
Toshi MARUYAMA
6ed3730c46 remove trailing white-spaces from config/locales/it.yml
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12195 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-02 08:34:23 +00:00
Toshi MARUYAMA
0c0b2f817f Traditional Chinese translation updated by ChunChang Lo (#15022)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12194 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-10-02 04:44:46 +00:00
Jean-Philippe Lang
f399b31eff Test broken by r12192 (#2199).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12193 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 22:17:27 +00:00
Jean-Philippe Lang
e35640f3e8 Allows user to clear dates and text fields when bulk editing issues (#2199).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12192 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 19:27:00 +00:00
Toshi MARUYAMA
285baaff94 Japanese translation updated by Go MAEDA (#15011)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12190 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 11:26:50 +00:00
Toshi MARUYAMA
38e8703ed4 pdf: fix empty page attached when exporting (#13632)
Contributed by Jun NAITOH.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12189 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 10:16:16 +00:00
Toshi MARUYAMA
d8ddb2cee4 remove trailing white-spaces from app/models/custom_field.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12188 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 09:53:57 +00:00
Toshi MARUYAMA
31ccc32016 Slovak translation updated and changed by Katarína Nosková (#14901)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12187 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 08:34:54 +00:00
Toshi MARUYAMA
77c497daa0 Italian translation changed by Alberto Cennini (#14981)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12186 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 07:14:39 +00:00
Toshi MARUYAMA
cbe75f3b9f remove trailing white-spaces from config/locales/ru.yml
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12185 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 06:54:57 +00:00
Toshi MARUYAMA
9b00bba5b5 Russian numeric translation changed by Sergei Danilov (#14920)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12184 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 06:54:46 +00:00
Toshi MARUYAMA
166d67bf87 Dutch translation updated by Pieter Nicolai (#14896)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12182 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 05:34:57 +00:00
Toshi MARUYAMA
c72baca17c Dutch activerecord.errors.messages.too_long/too_short translation updated by Pieter Nicolai (#14896)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12181 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 05:34:46 +00:00
Toshi MARUYAMA
b6f2b982ab Norwegian translation updated by Lennart Nordgreen (#14886)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12180 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 05:07:34 +00:00
Toshi MARUYAMA
13f6cd6b71 revert r12175 (#14883)
revert jdbc adapter version to above 1.2.6
due to test failure by "stack level too deep".

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12179 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 03:25:06 +00:00
Toshi MARUYAMA
7c2f62c798 Japanese "notice_not_authorized" translation changed (#14995)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12177 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 02:37:31 +00:00
Toshi MARUYAMA
3e90b6bcbf Bulgarian translation updated by Ivan Cenov (#15007)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12176 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 02:37:20 +00:00
Toshi MARUYAMA
5259da5e80 Gemfile: update jdbc adapter version above 1.3.0 (#14883)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12175 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 02:01:25 +00:00
Toshi MARUYAMA
3bc1dd573a Gemfile: update ruby-openid version above 2.3.0 (#14919)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12173 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-30 00:18:26 +00:00
Toshi MARUYAMA
c136e6bc60 Gemfile: update jdbc adapter version above 1.2.6 (#14883)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12172 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-29 23:52:00 +00:00
Jean-Philippe Lang
a1addba26c Adds some css classes (#14767).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12171 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-29 15:39:56 +00:00
Jean-Philippe Lang
481a1311b7 Adds a project specific css class to body (#14767).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12170 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-29 15:34:25 +00:00
Jean-Philippe Lang
2012e635b0 Removed unused code (#14621).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12169 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-29 15:27:31 +00:00
Jean-Philippe Lang
30eaf86f29 Filling locales (#3413).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12168 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-29 11:51:32 +00:00
Jean-Philippe Lang
cfc05d310e Exclude attachments from incoming emails based on file name (#3413).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12167 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-29 11:50:49 +00:00
Jean-Philippe Lang
2c97f9ecde AJAX call on the issue form resets data entered during the call (#14621).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12166 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-29 10:29:29 +00:00
Jean-Philippe Lang
886284b33f REST API: custom fields definition (#11159).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12165 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-29 10:08:30 +00:00
Jean-Philippe Lang
4a36e09d49 migrate_from_trac.rake does not properly parse First Name and Last Name (#14592).
Patch by Craig Rodrigues.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12164 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-25 17:49:58 +00:00
Jean-Philippe Lang
5e2eedf2c5 Fixed that Mantis/Trac users are not imported because of password too short (#14590).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12163 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-25 17:47:29 +00:00
Jean-Philippe Lang
62b66e9b38 Prevents invalid SQL with invalid group_ids (#14902).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12162 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-25 17:35:59 +00:00
Jean-Philippe Lang
3ace406bba French translation for underscore (#14972).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12161 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-25 17:17:55 +00:00
Toshi MARUYAMA
11ae71c5b9 remove trailing white-space from test/functional/repositories_bazaar_controller_test.rb (#14931)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12157 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-18 14:37:25 +00:00
Toshi MARUYAMA
5aa8358f97 scm: fix annotate error with non ASCII author on Ruby 1.9 and Ruby 2.0 (#14931)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12156 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-18 14:22:44 +00:00
Toshi MARUYAMA
120689e7cb scm: bazaar: update test repository for non ASCII author (#14931)
* run "bzr branch --no-tree branch00 author_non_ascii"
* add revision to this branch

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12155 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-18 14:22:32 +00:00
Toshi MARUYAMA
bf0676e17a scm: git: fix indents of non ASCII path annotate test (#14931)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12153 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-18 13:23:09 +00:00
Toshi MARUYAMA
9c9b5e471c use assert_select instead of assert_tag in Git non ASCII path annotate test (#14931)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12150 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-18 10:36:38 +00:00
Toshi MARUYAMA
d604725b40 scm: remove unnecessary h() from annotate author (#14931)
Rails3 escapes by default.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12149 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-18 10:13:28 +00:00
Toshi MARUYAMA
8b794b5e83 scm: bazaar: add test for author html escaping (#14931)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12148 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-18 10:13:16 +00:00
Toshi MARUYAMA
ef87b1cee4 scm: bazaar: update test repository for author html escaping (#14931)
* run "bzr branch --no-tree branch00 author_escaping"
* add revision to this branch

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12147 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-18 10:13:05 +00:00
Toshi MARUYAMA
23c56501de scm: bazaar: split REPOSITORY_PATH to trunk in functional test (#14931)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12146 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-18 10:12:53 +00:00
Toshi MARUYAMA
9002477006 scm: git: use "--encoding=UTF-8" for blame (#14931)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12143 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-18 06:16:55 +00:00
Toshi MARUYAMA
da87e4b1ef scm: git: change non ASCII user name variable to instance variable (#14931)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12142 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-18 06:16:43 +00:00
Toshi MARUYAMA
eaf05a87b4 use assert_select instead of assert_tag in Bazaar annotate test (#14931)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12141 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-18 05:44:41 +00:00
Toshi MARUYAMA
72e48e6a68 use assert_select instead of assert_tag in Mercurial annotate test (#14931)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12140 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-18 05:01:35 +00:00
Toshi MARUYAMA
435df86757 fix test failure (#14931)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12139 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-18 04:19:27 +00:00
Toshi MARUYAMA
12e1499b06 code format cleanup app/views/repositories/annotate.html.erb (#14931)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12138 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-18 03:36:49 +00:00
Jean-Philippe Lang
4db3e0be80 Updates for 2.3.3
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12135 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-14 06:46:40 +00:00
Jean-Philippe Lang
59b935aa46 Filters show issues with unused custom fields (#13537).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12133 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-13 17:41:54 +00:00
Jean-Philippe Lang
ae7304dd00 Test for #14798.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12132 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-11 22:00:40 +00:00
Jean-Philippe Lang
cb747a34ef Wrong done_ratio calculation for parent with subtask having estimated_hours=0 ().
Patch by Daniel Felix.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12131 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-11 22:00:18 +00:00
Jean-Philippe Lang
e7931941a7 Typo (#14819).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12130 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-11 21:34:27 +00:00
Jean-Philippe Lang
9149425750 Remove EOLs from attachments filename (#14819).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12129 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-11 21:31:59 +00:00
Jean-Philippe Lang
02fca76c13 Strip eols from file names (#14819).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12128 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-11 19:19:24 +00:00
Jean-Philippe Lang
06efcaddfa Fixed usage of #attribute_present? in UserPreference (#13008).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12126 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-10 17:39:49 +00:00
Toshi MARUYAMA
15ab64488a remove trailing white-space from app/models/journal.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12121 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-05 11:14:30 +00:00
Toshi MARUYAMA
0fc21282d5 fix Russian "description_date_range_interval" translation misprint (#14501)
Contributed by Artem Kondratyev.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12120 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-09-05 10:43:30 +00:00
Toshi MARUYAMA
4212654b64 fix wrong Russian translation in close project message (#14697)
Contributed by Artur Gadelshin.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12118 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-15 13:54:13 +00:00
Toshi MARUYAMA
81ad6501ef Portuguese translation for trunk updated by Lije Also (#14682)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12116 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-14 05:43:02 +00:00
Toshi MARUYAMA
1f196787c8 Portuguese translation for 2.3-stable updated by Lije Also (#14682, #14686)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12115 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-14 05:42:49 +00:00
Toshi MARUYAMA
4a2f9685bb Traditional Chinese translation for wiki_syntax.html by ChunChang Lo (#14684)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12114 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-14 03:51:02 +00:00
Toshi MARUYAMA
69714f4a07 use escaping html in wiki_syntax.html
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12113 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-13 10:52:53 +00:00
Toshi MARUYAMA
b188a05713 fix icon image paths of en-GB wiki syntax help (#14630)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12112 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-13 09:48:14 +00:00
Toshi MARUYAMA
e574aad6d7 Traditional Chinese translation for wiki_syntax by ChunChang Lo (#14677)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12111 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-13 09:09:51 +00:00
Toshi MARUYAMA
bda60769ea Japanese wiki_syntax_detailed.html translation updated by Go MAEDA (#14676)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12110 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-13 09:09:39 +00:00
Toshi MARUYAMA
e4fc36fa1b French wiki_syntax.html and wiki_syntax_detailed.html updated by Thomas Godard (#14670)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12109 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-13 02:18:30 +00:00
Toshi MARUYAMA
a3c30bf234 remove svn:executable from lib/plugins/rfpdf excluding lib/fonts/ttf2ufm/ttf2ufm(.exe)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12108 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-10 09:52:40 +00:00
Toshi MARUYAMA
98ac4c0baf remove unused lib/plugins/rfpdf/lib/fpdf/fpdf_eps.rb
This source has broken syntax "when :" on Ruby 1.9.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12107 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-10 09:37:10 +00:00
Toshi MARUYAMA
556cbad5c0 Japanese wiki_syntax.html translation updated by Go MAEDA (#14659)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12106 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-10 09:36:59 +00:00
Toshi MARUYAMA
d769b8080d German translation for member inheritance changed by Daniel Felix (#14657)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12105 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-10 08:42:36 +00:00
Toshi MARUYAMA
816a6e4b1f Bulgarian translation updated by Ivan Cenov (#14651)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12104 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-09 08:11:05 +00:00
Toshi MARUYAMA
2aa4f77fb0 German wiki_syntax.html translation updated by Daniel Felix (#14649)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12103 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-09 02:19:22 +00:00
Toshi MARUYAMA
b5b0d7396b German translation updated by Daniel Felix (#14647)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12102 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-09 01:47:59 +00:00
Toshi MARUYAMA
bdf6bd3355 Spanish translation updated by Thomas Godard (#14645)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12101 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-09 01:47:48 +00:00
Toshi MARUYAMA
8254cd2381 fix icon image paths of wiki syntax help (#14630)
Contributed by Go MAEDA.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12100 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-09 00:52:09 +00:00
Toshi MARUYAMA
adebdc835f code format cleanup app/views/projects/settings/_members.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12099 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-09 00:42:24 +00:00
Toshi MARUYAMA
3acefa8923 remove unneeded h() from app/views/projects/settings/_members.html.erb
Rails3 escapes by default.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12098 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-09 00:42:12 +00:00
Toshi MARUYAMA
4a11737d1c change member save button from :button_change to :button_save (#13745)
Contributed by Daniel Felix.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12097 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-09 00:09:06 +00:00
Toshi MARUYAMA
0be69b8b04 copy English wiki syntax helps to other languages (#14630)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12096 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-08 03:49:00 +00:00
Toshi MARUYAMA
43da3859bc revert r12094 (#14630)
r12094 lost "svn copy".

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12095 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-08 03:46:39 +00:00
Toshi MARUYAMA
e4c13efed7 copy English wiki syntax helps to other languages (#14630)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12094 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-08 03:38:50 +00:00
Toshi MARUYAMA
7394aeaa32 move English wiki syntax helps to en sub directory (#14630)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12093 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-08 03:38:21 +00:00
Toshi MARUYAMA
9fc4efcdd9 remove trailing white-spaces from public/help/wiki_syntax_detailed.html
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12092 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-08 03:38:09 +00:00
Toshi MARUYAMA
62bbd52452 Japanese translation updated by Go MAEDA (#14631)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12091 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-07 23:48:15 +00:00
Toshi MARUYAMA
c93dd877e9 code format cleanup app/views/projects/index.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12090 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-07 23:48:03 +00:00
Toshi MARUYAMA
e05f54819b Traditional Chinese translation updated by ChunChang Lo (#14625)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12089 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-07 07:18:52 +00:00
Toshi MARUYAMA
33ef601b12 gender neutral source comment at app/controllers/my_controller.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12088 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-06 06:27:30 +00:00
Toshi MARUYAMA
ae2b47afd6 code format cleanup app/models/issue.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12087 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-06 06:27:16 +00:00
Jean-Philippe Lang
85d4ac372a Submit handler should be live as well (#14615).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12086 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-05 18:32:18 +00:00
Jean-Philippe Lang
936ef250b4 Add hooks for user preferences (#14614).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12085 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-05 18:29:29 +00:00
Jean-Philippe Lang
cb90cdcc15 Warn me when leaving a page with unsaved text doesn't work when editing an update note (#14615).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12084 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-05 18:12:34 +00:00
Jean-Philippe Lang
fbffe332e2 Removed hardcoded string (#3872).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12083 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-05 18:04:20 +00:00
Jean-Philippe Lang
fa51c8601d Adds field_must_change_passwd string to locales (#3872).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12082 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-05 18:00:42 +00:00
Jean-Philippe Lang
b764e39847 Option to force a user to change his password (#3872).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12081 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-05 17:58:33 +00:00
Jean-Philippe Lang
bd4fba08e5 One click filter in search view (#2865).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12080 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-05 17:19:49 +00:00
Jean-Philippe Lang
fd1b060705 Fixed that standard fields disabled still appear in email notifications (#14584).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12079 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-05 17:08:26 +00:00
Jean-Philippe Lang
b19b902345 Moved CUSTOM_FIELDS_TABS out of the model.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12077 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-04 10:26:54 +00:00
Jean-Philippe Lang
b900ea8e2f Default data loader raises an error when called from the rake task (#14607).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12076 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-04 10:18:46 +00:00
Toshi MARUYAMA
e13814a59c remove trailing white-spaces from ApplicationHelper
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12075 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-03 13:23:32 +00:00
Toshi MARUYAMA
60fa32d51a replace tab to space at ApplicationHelper
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12074 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-03 13:23:21 +00:00
Toshi MARUYAMA
7711e37da4 remove ineffective "logger.info" and "logger.error" check from MailHandler model (#14598)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12073 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-03 10:46:53 +00:00
Toshi MARUYAMA
f5658df8db add example on how to run a single test to documentation (#14588)
Contributed by Mischa The Evil.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12072 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-08-01 03:31:54 +00:00
Toshi MARUYAMA
c49451eb10 not use assert_not_nil in Errors#[]
r7593 etc. replaced Rails2 Errors#on.
Rails3 Errors#[] always return array.
So, Rails3 Errors#[] is always not nil.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12070 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-30 08:23:54 +00:00
Toshi MARUYAMA
c20b1d64a7 add missing fixture to test/unit/issue_relation_test.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12069 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-30 08:23:42 +00:00
Jean-Philippe Lang
3df08b02b4 Broken tests (#14491).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12068 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-29 19:08:01 +00:00
Jean-Philippe Lang
1502da5726 Use the default project when receiving an email with an invalid project keyword (#14491).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12067 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-29 16:37:45 +00:00
Jean-Philippe Lang
27c3299f32 Fixed that open/closed counts on issues summary are not displayed with SQLServer (#14369).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12060 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-28 16:38:09 +00:00
Jean-Philippe Lang
df7e56b13c Autocomplete fields rendering issue with alternate theme (#14340).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12059 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-28 15:36:52 +00:00
Jean-Philippe Lang
4a70a319c5 Filtering issues on "related to" may ignore other filters (#14401).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12058 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-28 15:29:31 +00:00
Jean-Philippe Lang
76e48c3914 Spent time details and report should ignore 'Setting.display_subprojects_issues?' (#14415).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12057 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-28 15:16:14 +00:00
Jean-Philippe Lang
474453d2b0 Additional status transitions for assignees do not work if assigned to a group (#14447).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12056 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-28 14:58:06 +00:00
Jean-Philippe Lang
9a0db9cb88 Fixed: warning: class variable access from toplevel on Ruby 2.0 (#14511).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12052 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-28 11:57:39 +00:00
Jean-Philippe Lang
642a892c05 Missing Sort Column Label and Center Align on Admin-Enumerations (#14516).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12051 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-28 11:53:28 +00:00
Jean-Philippe Lang
f3241385cd Adds missing html titles (#14517).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12050 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-28 11:50:18 +00:00
Jean-Philippe Lang
1e738fbaca Set titles on Groups pages (#14517)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12049 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-28 11:23:22 +00:00
Jean-Philippe Lang
2f9050115b Adds a helper for building h2 tags and setting html_title (#14517).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12048 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-28 11:21:58 +00:00
Toshi MARUYAMA
3700378764 svn propset svn:eol-style native test fixtures (#14562)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12047 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-28 11:02:55 +00:00
Toshi MARUYAMA
670d2b6e2b fix diff of CJK(Chinese/Japanese/Korean) is broken on Ruby 1.8 (#14562)
Contributed by Jun NAITOH.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12046 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-28 11:00:02 +00:00
Jean-Philippe Lang
0ac3afebc6 Don't use finder options.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12045 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-28 10:15:53 +00:00
Jean-Philippe Lang
ef8dd0f64b Preload some associations.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12044 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-28 10:13:48 +00:00
Jean-Philippe Lang
21fc903c04 Fixed that sorting time entries by custom field raises a SQL error (#14366).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12042 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-28 09:59:34 +00:00
Jean-Philippe Lang
dc5e5eca6b Fixed that displaying time entries with custom field column raises an error (#5037).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12041 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-24 18:18:08 +00:00
Toshi MARUYAMA
4069f95fd1 Spanish translations for trunk updated by Jorge López (#14521)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12039 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-24 09:52:38 +00:00
Toshi MARUYAMA
26c30a04ba Spanish translations for 2.3.x updated by Jorge López (#14531, #14521)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12038 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-24 09:52:27 +00:00
Toshi MARUYAMA
053c15df8a Russian translation for trunk updated by Alex Stein (#14501)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12035 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-19 16:06:24 +00:00
Toshi MARUYAMA
b6e6fb1fac Russian translation for 2.3-stable updated by Alex Stein (#14502, #14501)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12034 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-19 16:06:13 +00:00
Toshi MARUYAMA
a43eb91f45 update ruby-openid version to 2.2.3
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12033 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-19 15:21:14 +00:00
Toshi MARUYAMA
76ab4710a8 Bulgarian translation updated by Ivan Cenov (#14473)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12031 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-18 08:32:46 +00:00
Toshi MARUYAMA
b6dd64aac1 Japanese translation updated by Go MAEDA (#14478)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12030 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-18 08:32:34 +00:00
Toshi MARUYAMA
7bb6dabf23 Traditional Chinese translation for trunk updated by ChunChang Lo (#14458)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12029 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-18 08:32:23 +00:00
Toshi MARUYAMA
3c4f47acc9 Traditional Chinese translation for 2.3-stable updated by ChunChang Lo (#14485, #14458)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12028 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-18 08:32:11 +00:00
Jean-Philippe Lang
01a9e17c49 CVS root_url not recognized when connection string does not include port (#14422).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12027 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-15 21:06:54 +00:00
Jean-Philippe Lang
9ca8b20d55 Don't hardcode news model in Comment.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12026 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-15 20:53:23 +00:00
Jean-Philippe Lang
0e3dfa8de4 Updates for 2.3.2 release.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12024 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-14 14:51:01 +00:00
Jean-Philippe Lang
085417bdbb Additional tests for AccountController.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12022 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-14 14:39:31 +00:00
Jean-Philippe Lang
205eda8b33 Use AR callbacks instead of observers (removed in Rails4) for notifications.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12021 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-14 14:26:27 +00:00
Jean-Philippe Lang
010bfc56e1 Ability to save Gantt query filters (#7836).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12020 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-14 13:41:30 +00:00
Jean-Philippe Lang
3c9263221d Test failures with ruby1.8.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12019 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-13 21:35:33 +00:00
Jean-Philippe Lang
13bf8dc8bf ruby1.8 compatibility.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12018 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-13 12:15:24 +00:00
Jean-Philippe Lang
01f259be0d Adds a test for CvsAdapter#root_url_path (#14422).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12017 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-13 11:03:37 +00:00
Jean-Philippe Lang
594589e0ec Use Hash#reject that returns a Hash with ruby1.8 when Hash#select that returns an Array.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12016 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-13 10:39:36 +00:00
Jean-Philippe Lang
0087d237f7 Don't notify users about relations that are not visible (#1005).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12015 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-13 10:32:48 +00:00
Jean-Philippe Lang
7509dda1ff Fixed that relations to issues that are not visible are displayed in the issue history (#1005).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12014 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-13 09:56:58 +00:00
Jean-Philippe Lang
5fbc7f8f1f Fills locales with new strings.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12013 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-13 09:21:58 +00:00
Jean-Philippe Lang
628d05629b Role-based issue custom field visibility (#5037).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12012 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-13 09:20:11 +00:00
Jean-Philippe Lang
a74d55edd9 Removed dead code.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12011 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-13 08:13:34 +00:00
Jean-Philippe Lang
8ff33ac9f7 Log email delivery errors (#14403).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12010 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-13 08:11:20 +00:00
Jean-Philippe Lang
6ecd90e7ff Exception message may not be UTF-8 encoded.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12009 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-12 20:16:59 +00:00
Jean-Philippe Lang
0a4d2affd8 Fixed one query per member on project settings.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12008 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-11 19:57:15 +00:00
Jean-Philippe Lang
9cb68f7b29 One query is enough.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12007 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-11 19:41:48 +00:00
Jean-Philippe Lang
80b1a73ccf Adds 'assigned-to-my-group' css class to issues that are assigned to a user's group (#12681).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12006 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-11 19:35:40 +00:00
Jean-Philippe Lang
f3d1aa5359 Issue-notes Redmine links: append actual note reference to rendered links (#12912).
Patch by YOSHITANI Mitsuhiro.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12005 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-11 19:18:37 +00:00
Jean-Philippe Lang
f5768cc99b Useless "edit" link in workflow menu (#12824).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12004 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-11 19:12:08 +00:00
Jean-Philippe Lang
bc4785ca60 Add more info about the ruby version (#14419).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@12003 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-11 18:45:43 +00:00
Jean-Philippe Lang
888c3581eb Role based custom queries (#1019).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11994 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-11 17:45:10 +00:00
Toshi MARUYAMA
4545b906b4 gender neutral source comment at test/unit/journal_test.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11993 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-06 01:02:44 +00:00
Toshi MARUYAMA
b38de1f5e2 gender neutral source comment at test/unit/issue_test.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11992 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-06 01:02:33 +00:00
Toshi MARUYAMA
7ee06dfe08 gender neutral source comment at test/integration/account_test.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11991 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-06 01:02:21 +00:00
Toshi MARUYAMA
c5ca4e2622 gender neutral source comment at lib/tasks/migrate_from_trac.rake
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11990 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-06 01:02:10 +00:00
Toshi MARUYAMA
edb6e245cf gender neutral source comment at app/models/user.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11989 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-06 00:04:58 +00:00
Toshi MARUYAMA
e1ca4a8663 gender neutral source comment at app/models/mailer.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11988 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-06 00:04:47 +00:00
Toshi MARUYAMA
b1b721ff6d gender neutral source comment at app/controllers/projects_controller.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11987 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-06 00:04:35 +00:00
Toshi MARUYAMA
de6ff11164 remove trailing white-space from test/unit/issue_test.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11986 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-05 22:50:48 +00:00
Toshi MARUYAMA
6db84ab0c1 remove trailing white-space from test/integration/account_test.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11985 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-07-05 22:50:29 +00:00
Toshi MARUYAMA
bc18590da3 Slovene translation changed by Zdravko Balorda (#14360)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11983 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-26 11:42:40 +00:00
Toshi MARUYAMA
e4e1c7a0f2 fix Latvian "button_log_time" translation by Arnis Juraga (#14346)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11982 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-26 10:29:45 +00:00
Toshi MARUYAMA
7dfc6545ff replace "email.yml" to "configuration.yml" in pl.yml (#9996)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11980 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-15 11:49:22 +00:00
Toshi MARUYAMA
9bf4288af9 not run Capybara tests on the CI server (#12822)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11979 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-14 14:39:48 +00:00
Toshi MARUYAMA
56f9354998 prevent UI test failure randomly
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11978 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-14 14:06:04 +00:00
Toshi MARUYAMA
484a3ffc8a increase Capybara.default_wait_time from 12 to 20 (#12822)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11977 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-14 12:42:03 +00:00
Toshi MARUYAMA
c17347b7f7 increase Capybara.default_wait_time from 7 to 12 (#12822)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11976 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-14 10:50:59 +00:00
Toshi MARUYAMA
9b549fdfe9 shorten comment lines at test/ui/base.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11975 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-14 10:50:48 +00:00
Toshi MARUYAMA
17378152bf use database_cleaner (#12822)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11974 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-14 09:59:21 +00:00
Toshi MARUYAMA
b29288c50a prevent UI test failure randomly
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11973 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-14 08:30:53 +00:00
Toshi MARUYAMA
784440691c increase Capybara.default_wait_time from 6 to 7 (#12822)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11972 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-14 07:31:11 +00:00
Toshi MARUYAMA
6da348c3e6 prevent UI test failure randomly
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11971 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-14 07:31:00 +00:00
Toshi MARUYAMA
6ccb68bd46 prevent UI test failure randomly
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11970 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-14 05:14:29 +00:00
Toshi MARUYAMA
eeb290d650 German translation updated by Daniel Felix (#14277)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11969 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-14 04:42:58 +00:00
Toshi MARUYAMA
0396c99945 increase Capybara.default_wait_time from 5 to 6 (#12822)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11968 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-14 04:24:02 +00:00
Jean-Philippe Lang
2f53246c13 Code cleanup.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11967 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-13 19:31:43 +00:00
Jean-Philippe Lang
07d88851bf Fixed tests broken by r11965.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11966 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-12 21:55:39 +00:00
Jean-Philippe Lang
e978b3ace0 Adds User#builtin_role.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11965 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-12 19:38:43 +00:00
Jean-Philippe Lang
cd716e311a Preload boards projects.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11964 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-12 19:34:23 +00:00
Jean-Philippe Lang
f9ddb562d5 Cleanup of finders with :conditions option.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11963 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-12 19:13:25 +00:00
Jean-Philippe Lang
136cdc765a Don't redirect XHR requests to /login.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11962 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-12 16:49:12 +00:00
Jean-Philippe Lang
60d2a5e322 Use #find_issues as before filter for issues context menu.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11961 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-11 18:33:06 +00:00
Jean-Philippe Lang
7371077fa2 Code cleanup.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11960 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-11 18:29:29 +00:00
Jean-Philippe Lang
e0c7eb25a4 Adds Watcher.any_watched? to check if at least one object of a collection is watched.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11959 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-11 18:25:05 +00:00
Jean-Philippe Lang
2113b88db3 Code cleanup.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11958 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-11 18:18:02 +00:00
Jean-Philippe Lang
3e9aeea75d Perf: preload a few associations for bulk operations.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11957 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-11 17:24:17 +00:00
Jean-Philippe Lang
32464f4912 Perf: don't load all projects.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11956 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-11 16:54:48 +00:00
Toshi MARUYAMA
0ba6ece2fd Bulgarian translation updated by Ivan Cenov (#14252)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11955 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-11 07:58:01 +00:00
Toshi MARUYAMA
cb140248ea remove trailing white-space from app/models/user.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11954 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-10 08:48:49 +00:00
Toshi MARUYAMA
ebb73fa258 set html lang by user locale (#14206)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11952 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-10 01:41:30 +00:00
Toshi MARUYAMA
5a7f656303 run test:ui on CI Server Ruby 1.9.3 or higher (#12822)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11951 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-10 00:51:37 +00:00
Jean-Philippe Lang
2d02a2692a Resets strings that don't mention that an email was sent for activating the account.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11950 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-09 10:28:03 +00:00
Jean-Philippe Lang
52af9a1766 Adds the email address to the flash message after registeration.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11949 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-09 10:23:31 +00:00
Jean-Philippe Lang
86cfa025ed Adds a test for User.try_to_login with active_only set to false.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11948 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-09 10:12:02 +00:00
Jean-Philippe Lang
f64dc99f8a Adds i18n strings (#14228).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11947 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-09 10:06:00 +00:00
Jean-Philippe Lang
4bd874ab46 Adds a way for a registered user to get a new action email (#14228).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11946 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-09 10:01:56 +00:00
Toshi MARUYAMA
ec46d4315c svn propset svn:eol-style native CONTRIBUTING.md
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11944 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-08 10:11:47 +00:00
Toshi MARUYAMA
597b2ad2ea add CONTRIBUTING.md for github pull request
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11943 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-08 10:09:02 +00:00
Toshi MARUYAMA
a0423f4eb1 fix that project auto generation fails when projects created in the same time (#14242)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11942 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-08 09:50:34 +00:00
Jean-Philippe Lang
2a00c33a61 Splits tests (#1005).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11941 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-06 16:25:51 +00:00
Jean-Philippe Lang
d90f46a5da Prepends issue numbers with a number sign (#1005).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11940 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-06 16:22:18 +00:00
Jean-Philippe Lang
019f57e5c7 Fixed that journal details about issue relations may disclose issues that are not visible (#1005).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11939 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-06 16:19:53 +00:00
Toshi MARUYAMA
60a8230209 fix three png transparency (#14223)
Contributed by W Snyder.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11938 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-06 08:22:01 +00:00
Toshi MARUYAMA
346bbcb80a German translation: grammar + spelling (#14222)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11937 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-06 06:47:20 +00:00
Toshi MARUYAMA
bbd0cb269d remove redundant empty lines from PluginTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11936 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-06 06:47:10 +00:00
Toshi MARUYAMA
9aad7c3907 Japanese translation updated by Go MAEDA (#14224)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11934 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-06 05:39:29 +00:00
Toshi MARUYAMA
442532e316 remove trailing white-spaces from lib/redmine/plugin.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11933 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-06 05:09:46 +00:00
Toshi MARUYAMA
6ab02e535f translate x_hours in many languages (#14221)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11932 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-06 05:09:35 +00:00
Jean-Philippe Lang
8cea7d8cf2 Don't validate start date when updating an issue without changing it (#14086).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11931 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-05 19:56:59 +00:00
Toshi MARUYAMA
6327bdc6f8 Bulgarian translation updated by Ivan Cenov (#14209)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11930 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-05 04:37:12 +00:00
Jean-Philippe Lang
4c2776c634 Really adjusts error message in tests (#14086).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11928 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-04 17:41:58 +00:00
Jean-Philippe Lang
b0c7884976 Adjusts error message in tests (#14086).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11927 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-04 17:32:13 +00:00
Jean-Philippe Lang
46085644ed Adds a specific error message for when the start date is too earlier than the minimum start date (#14086).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11926 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-04 17:17:48 +00:00
Toshi MARUYAMA
01411ab567 prevent coderay "warning: already initialized constant" on Ruby 1.8.7 (#13692)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11925 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-04 14:07:46 +00:00
Toshi MARUYAMA
7e4d0209bb increase Capybara.default_wait_time from 4 to 5 (#12822)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11923 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-04 11:57:49 +00:00
Toshi MARUYAMA
1fd7540b85 pdf: replace "id_width" parameter name to original "col_id_width" (#14178)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11921 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-04 11:02:45 +00:00
Toshi MARUYAMA
7bc0c26198 pdf: restore "id_width" parameter of issues_to_pdf_draw_borders (#14178)
Contributed by Massimo Rossello.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11920 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-04 10:54:55 +00:00
Toshi MARUYAMA
f41d917141 Italian translation for 2.3-stable by Riccardo Rocca (#14196)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11919 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-04 10:29:18 +00:00
Jean-Philippe Lang
29c3b34641 Adds SCM versions in script/about output.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11918 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-01 16:32:29 +00:00
Jean-Philippe Lang
e27deb1ece Query#add_custom_fields_filters now takes a custom fields scope.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11917 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-01 10:56:12 +00:00
Jean-Philippe Lang
bf76b3b286 Project#all_issue_custom_fields now returns a scope.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11916 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-06-01 10:26:17 +00:00
Jean-Philippe Lang
5a90b6d0b5 Fixed that project name is not properly escaped in issue filters (#14186).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11915 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-31 20:47:38 +00:00
Toshi MARUYAMA
bc75b15546 use English "Tag" and "Branch" in pt-BR locale (#14180)
patch by Marcela Oliveira.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11913 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-31 10:20:08 +00:00
Toshi MARUYAMA
2ca2634138 pt-BR translation improved by Marcela Oliveira (#14180)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11912 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-31 10:19:57 +00:00
Toshi MARUYAMA
0163ef8bfb pt-BR translation for 2.3-stable updated by Marcela Oliveira (#14182, #14180)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11911 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-31 09:51:05 +00:00
Toshi MARUYAMA
57c347d8f8 back out r11907 (#14151)
German "x_days" translation changed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11910 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-30 12:04:38 +00:00
Toshi MARUYAMA
a4394e877e add changeset comment in revision page title (#14138)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11909 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-30 08:05:44 +00:00
Toshi MARUYAMA
d2192bba02 add test of revision page title (#14138)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11908 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-30 07:41:17 +00:00
Toshi MARUYAMA
71afcaf43b German "x_days" translation changed by Filou Centrinov (#14151)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11907 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-30 07:41:06 +00:00
Jean-Philippe Lang
73aadc4900 Use uid_ methods for retrieving IMAP messages (#14101).
Patch by Pierre Pretorius.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11906 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-28 18:41:14 +00:00
Jean-Philippe Lang
131dc3a8fc Disconnect and logout from IMAP after mail receive (#14103).
Patch by Pierre Pretorius.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11905 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-28 18:17:36 +00:00
Jean-Philippe Lang
69496179d4 Adds a button to duplicate a workflow permission to the next statuses.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11904 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-28 10:59:04 +00:00
Toshi MARUYAMA
4dbe2e7062 remove trailing white-space from app/models/mailer.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11902 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-25 05:35:13 +00:00
Toshi MARUYAMA
672331d7e4 German translation of x_hours updated by Filou Centrinov (#14145)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11901 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-25 04:31:51 +00:00
Toshi MARUYAMA
1e18c23095 use document.referrer instead of history.length (#13697)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11900 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-24 07:21:56 +00:00
Toshi MARUYAMA
54478d1e08 remove trailing white-space from app/views/repositories/_breadcrumbs.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11899 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-24 06:59:41 +00:00
Toshi MARUYAMA
f085508121 gantt: sort versions by start date (#7335)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11898 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-21 13:42:34 +00:00
Toshi MARUYAMA
8ea4e79964 gantt: sort issues by start date (#7335)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11897 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-21 13:42:19 +00:00
Toshi MARUYAMA
596366b062 upgrade mocha 0.14 and remove deprecation warning
<pre>
Mocha deprecation warning: Change `require 'mocha'` to `require 'mocha/setup'`.
</pre>

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11896 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-21 12:57:11 +00:00
Toshi MARUYAMA
f4637c38b4 fix yaml syntax and comment out (#14060)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11895 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-21 10:00:53 +00:00
Toshi MARUYAMA
9d62a564df remove unneeded escaping at app/views/journals/diff.html.erb
Rails3 escapes by default.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11894 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-21 07:11:36 +00:00
Toshi MARUYAMA
83d148242a fix back-button on description diff page in case of no browser history (#13697)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11893 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-21 07:11:25 +00:00
Toshi MARUYAMA
38f6c588ca code layout clean up test_bulk_copy_should_allow_not_changing_the_issue_attributes of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11892 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-19 04:03:31 +00:00
Toshi MARUYAMA
7def5b551d code layout clean up test_bulk_update_with_some_failures_should_show_errors of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11891 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-19 04:03:21 +00:00
Toshi MARUYAMA
a968c1196e code layout clean up test_bulk_update_parent_id of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11890 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-19 04:03:11 +00:00
Toshi MARUYAMA
e3d47acb0b code layout clean up test_bulk_edit_should_only_propose_statuses_allowed_for_all_issues of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11889 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-19 04:03:01 +00:00
Toshi MARUYAMA
098a38bb3a code layout clean up test_create_as_copy_should_add_relation_with_copied_issue of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11888 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-19 04:02:50 +00:00
Toshi MARUYAMA
dbc7369d9d adjust functional IssuesControllerTest (#1005)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11887 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-19 03:40:22 +00:00
Toshi MARUYAMA
b3a6555b30 remove "del" tag from deleted issue relation (#1005)
It is confused with deleted issue.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11886 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-19 02:09:49 +00:00
Toshi MARUYAMA
1f9e1ca318 add journal after creating/deleting issue relation (#1005)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11885 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-19 02:09:39 +00:00
Toshi MARUYAMA
e5e73a56a7 svn:eol-style native datepicker.js (#14024)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11884 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-19 01:09:45 +00:00
Toshi MARUYAMA
0e20ec697b set default issue start/due datepicker from due/start date (#14024)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11883 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-19 01:06:25 +00:00
Toshi MARUYAMA
cbb8b12ba4 increase Capybara.default_wait_time from 3 to 4 (#12822)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11882 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-19 01:06:14 +00:00
Toshi MARUYAMA
eeeada0773 code layout clean up VersionTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11881 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-19 01:06:04 +00:00
Toshi MARUYAMA
bbca694881 remove empty setup method from VersionTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11880 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-19 01:05:53 +00:00
Toshi MARUYAMA
160f6cd361 add test of current issue start and due date datepicker (#14024)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11879 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-19 00:27:39 +00:00
Toshi MARUYAMA
11b24ab64b replace non ASCII literal to hexadecimal at ApplicationHelperTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11878 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 23:06:53 +00:00
Toshi MARUYAMA
360bda7e68 include Redmine::I18n in ApplicationHelperTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11877 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 22:36:58 +00:00
Toshi MARUYAMA
0c6e2feeaa backout r11875 ApplicationHelperTest change
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11876 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 22:36:45 +00:00
Jean-Philippe Lang
bd8b509986 Include Redmine::I18n in helpers tests.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11875 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 20:29:40 +00:00
Jean-Philippe Lang
2e67ffe769 Code cleanup.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11874 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 20:09:59 +00:00
Jean-Philippe Lang
ed364c9114 Code cleanup.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11873 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 19:58:43 +00:00
Jean-Philippe Lang
1093454193 Adds markings to emails generated by private comments (#12888).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11869 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 17:24:23 +00:00
Toshi MARUYAMA
de394f5f74 fix unit VersionTest failure
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11868 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 12:55:24 +00:00
Toshi MARUYAMA
23527da802 backout r11865 test/object_helpers.rb changes
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11867 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 12:07:43 +00:00
Jean-Philippe Lang
79c8fea12f Removed debug log (#14038).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11866 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 09:31:43 +00:00
Jean-Philippe Lang
61dfab12fd Removed some shoulda context.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11865 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 09:27:48 +00:00
Jean-Philippe Lang
474c010746 Removed some shoulda context.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11864 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 09:14:10 +00:00
Jean-Philippe Lang
8f7b69f77e Removed some shoulda context.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11863 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 08:57:27 +00:00
Jean-Philippe Lang
0d4bb7558f Removed some shoulda context.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11862 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 08:27:53 +00:00
Jean-Philippe Lang
5b29964512 User #where instead of :conditions.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11861 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 07:49:13 +00:00
Jean-Philippe Lang
2c67e9e0d7 Moved links to block titles on "My page".
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11860 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 07:47:34 +00:00
Jean-Philippe Lang
6b03c741ac Adds a link on "My Page" to view all my spent time (#13157).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11859 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 07:39:26 +00:00
Jean-Philippe Lang
45a9b9954a Highlighting of source link target line for annotate view (#13746).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11858 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 07:10:14 +00:00
Jean-Philippe Lang
6e35d2f0e9 Highlighting of source link target line (#13746).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11857 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-18 07:09:02 +00:00
Toshi MARUYAMA
997bfbe78f gantt: add test to sort issues by current logic (#7335)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11856 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-17 22:59:52 +00:00
Toshi MARUYAMA
6aa63659aa gantt: change sort method to class method (#7335)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11855 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-17 22:59:39 +00:00
Jean-Philippe Lang
c90bf645f5 Fixed that submitting the form without selecting a value may raise raises an error with SQLServer (#13783).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11854 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-17 18:18:06 +00:00
Jean-Philippe Lang
d678959359 Add links to attachments in new issue email notification (#12293).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11853 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-17 16:51:09 +00:00
Toshi MARUYAMA
8bbc6d251e increase Capybara.default_wait_time from default 2 to 3 (#12822)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11852 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-17 04:08:06 +00:00
Jean-Philippe Lang
eab2c74e10 Use a shallow block instead of the :shallow option that ignores routes scope (#14023).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11851 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-16 16:57:53 +00:00
Jean-Philippe Lang
35ca873269 Fixed that filtering may return unwanted blank values (#14051).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11850 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-16 16:29:59 +00:00
Toshi MARUYAMA
a4391db7cd enable configuration of OpenIdAuthentication.store (#14060)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11849 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-16 10:55:41 +00:00
Toshi MARUYAMA
f2a609c358 move filter order tests from helper to model.
r11372 (#13154) moves filter order logic from helper to model.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11848 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-16 10:55:27 +00:00
Toshi MARUYAMA
559aa626cd increase base height of author lines on 'Commits per author' graph (#14068, #1983)
Contributed by Mischa The Evil.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11847 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-16 04:29:51 +00:00
Toshi MARUYAMA
5ef5b3202d remove width and height from repository stats embed tags (#1983, #13486)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11846 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-16 04:29:39 +00:00
Jean-Philippe Lang
b3d80d50a3 Fixed that ordered/unordered lists inside table cell are mangled (#14038).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11845 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-14 16:29:59 +00:00
Toshi MARUYAMA
28ca9d240a run test:ui in CI Server on only Ruby 2.0 (#12822)
UI tests fails randomly on Ruby 1.9.3.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11844 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-13 23:16:02 +00:00
Jean-Philippe Lang
ece5232110 Fixed that values of custom fields are not kept in issues when copying a project (#13910).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11843 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-13 19:52:37 +00:00
Jean-Philippe Lang
7e41730293 Display error messages when attachment validation fails (#13949).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11842 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-13 18:50:04 +00:00
Jean-Philippe Lang
288c3b863d Fixed that JS warning is not displayed when attachment maximum size is 0 (#13949).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11841 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-13 18:30:56 +00:00
Jean-Philippe Lang
4a59b869c0 Update notified_project_ids while saving record.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11840 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-13 17:11:38 +00:00
Jean-Philippe Lang
10ed306b19 Fixed that locking and unlocking a user resets the email notification checkbox (#14020).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11839 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-13 16:38:08 +00:00
Jean-Philippe Lang
0dce4761a8 Disable autofetching of repository changesets if projects are closed (#13945).
Patch by Mischa The Evil.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11838 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-12 10:05:35 +00:00
Jean-Philippe Lang
9b7d312a0e Fix handling multiple text parts in email (#13646).
Patch by Alex Shulgin.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11834 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-12 09:38:20 +00:00
Jean-Philippe Lang
76a3298306 Issue#children is never nil (#14015).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11833 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-12 08:49:54 +00:00
Jean-Philippe Lang
922acdbcc2 Check inclusion only once (#14015).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11832 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-12 08:45:40 +00:00
Jean-Philippe Lang
a7102db8c4 Replaces camelcase variable names (#14015).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11831 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-12 08:42:41 +00:00
Jean-Philippe Lang
a2b6088772 Removes some empty lines (#14015).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11830 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-12 08:41:21 +00:00
Jean-Philippe Lang
cf30a68312 Removes then's (#14015).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11829 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-12 08:39:18 +00:00
Jean-Philippe Lang
8c9bba1cbf Replaces camelcase variable names (#14015).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11828 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-12 08:37:54 +00:00
Jean-Philippe Lang
78dc37d8af Improved Issue#all_dependent_issues (#14015).
Patch by Jost Baron.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11827 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-12 08:33:21 +00:00
Jean-Baptiste Barth
ef153a5bca Improve plugins' Gemfile loading (#14028).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11826 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-11 11:19:21 +00:00
Toshi MARUYAMA
f9e6414de6 sync Lithuanian jQuery datepicker (#13674)
This is from following revision.
ce73a2688d

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11825 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-11 07:22:29 +00:00
Toshi MARUYAMA
b49ea330d1 prevent failure of test_create_issue_with_watchers at UI IssuesTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11824 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-10 09:22:57 +00:00
Toshi MARUYAMA
8a87ff96f9 code layout clean up app/views/issues/_attributes.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11823 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-10 06:44:45 +00:00
Toshi MARUYAMA
72a46e53ed prevent failure of test_create_issue_with_watchers at UI IssuesTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11822 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-10 05:51:31 +00:00
Toshi MARUYAMA
ed956ba5d4 use with_settings at test_post_create_without_start_date_and_default_start_date_is_creation_date of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11821 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-10 04:37:42 +00:00
Toshi MARUYAMA
e1ba9012c6 use with_settings at test_post_create_without_start_date_and_default_start_date_is_not_creation_date of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11820 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-10 04:37:31 +00:00
Toshi MARUYAMA
a3766c5281 use with_settings at test_get_new_with_default_start_date_is_creation_date of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11819 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-10 04:37:21 +00:00
Toshi MARUYAMA
af2053fe13 use with_settings at test_get_new_without_default_start_date_is_creation_date of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11818 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-10 04:37:09 +00:00
Toshi MARUYAMA
68ef3aeaa8 remove redundant empty lines from test_show_by_manager of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11817 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-10 03:50:44 +00:00
Toshi MARUYAMA
d65c0e8ed7 remove redundant empty lines from test_show_by_anonymous of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11816 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-10 03:50:33 +00:00
Toshi MARUYAMA
644455d56b remove redundant empty line from test_index_with_fixed_version_column of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11815 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-10 03:50:22 +00:00
Toshi MARUYAMA
4b5677101c remove redundant empty line from test_index_should_not_show_spent_hours_column_without_permission of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11814 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-10 03:50:11 +00:00
Toshi MARUYAMA
47235f7b23 remove redundant empty line from test_index_with_spent_hours_column of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11813 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-10 03:50:00 +00:00
Toshi MARUYAMA
2542afbc3b remove redundant empty lines from test_index_with_done_ratio_column of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11812 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-10 03:49:48 +00:00
Toshi MARUYAMA
83d3aaf170 remove redundant empty lines from test_index_with_date_column of IssuesControllerTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11811 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-09 16:14:16 +00:00
Toshi MARUYAMA
cd2776a96f run test:ui on CI Server Ruby 1.9.3 or higher (#12822)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11810 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-09 13:45:32 +00:00
Toshi MARUYAMA
e038d630d5 prevent assert_difference failure of test_bulk_watch_issues_via_context_menu at UI IssuesTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11809 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-09 13:45:21 +00:00
Toshi MARUYAMA
6d4e43f3fb prevent assert_difference failure of test_watch_issue_via_context_menu at UI IssuesTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11808 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-09 13:45:09 +00:00
Toshi MARUYAMA
aaa37be223 fix failure of test_remove_issue_watcher_from_sidebar at UI IssuesTest
<pre>
  2) Failure:
test_remove_issue_watcher_from_sidebar(Redmine::UiTest::IssuesTest) [test/ui/issues_test.rb:186]:
"Watcher.count" didn't change by -1.
<3> expected but was
<4>.
</pre>

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11807 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-09 13:03:41 +00:00
Toshi MARUYAMA
2b022ac097 install capybara on only Ruby 1.9.3 or higher (#12822)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11806 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-09 13:03:28 +00:00
Toshi MARUYAMA
00f15828a2 upgrade capybara to 2.1 (#12822)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11805 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-09 12:21:45 +00:00
Toshi MARUYAMA
9f41c7283c add more asserting to test_create_issue_with_watchers of ui issues_test
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11804 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-09 11:34:25 +00:00
Jean-Baptiste Barth
1e7c26d9a5 Document project links in ApplicationHelper#parse_redmine_links (#6689).
Contributed by Mischa The Evil


git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11803 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-08 07:59:14 +00:00
Toshi MARUYAMA
fe0293a110 sync Lithuanian jQuery datepicker (#13674)
This is from following revision.
49f9b849b9

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11802 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-08 03:51:04 +00:00
Toshi MARUYAMA
79e394a0c5 Enhanced Arabic translation by Amr Noaman (#13988)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11800 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-08 01:17:28 +00:00
Toshi MARUYAMA
5b95b6a6aa Swedish Translation for trunk updated by Nicklas Holm (#14003)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11799 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-07 23:38:11 +00:00
Toshi MARUYAMA
d994ff79f4 Swedish Translation for 2.3-stable updated by Nicklas Holm (#14003, #14005)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11798 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-07 23:37:59 +00:00
Jean-Baptiste Barth
0d2fb4503b Add documentation about horizontal rule syntax (#2427).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11797 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-07 06:22:40 +00:00
Jean-Baptiste Barth
b4c3bb0558 Fix Trac importer breaking on exotic characters with ruby 1.9+ (#13990).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11796 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-06 22:19:37 +00:00
Jean-Baptiste Barth
2b3111122e Ensure Tranc and Mantis importers don't reset global notification settings (#13989).
Contributed by Brandon Valentine


git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11795 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-06 20:39:03 +00:00
Toshi MARUYAMA
db3b3d3a1c Lithuanian "label_attachment" translation changed by Andrius Kriučkovas (#13674)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11794 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-05 10:58:19 +00:00
Toshi MARUYAMA
be0da7aaa8 Lithuanian "field_generate_password" translation updated by Andrius Kriučkovas (#13674)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11793 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-05 10:58:08 +00:00
Toshi MARUYAMA
2183c673d1 remove duplicate Lithuanian "error_attachment_too_big" translation keys (#13950)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11791 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-05 09:24:25 +00:00
Jean-Baptiste Barth
ec4dbbced5 Add status to /users/:id API for admins (#13948).
Patch by Kambiz Darabi


git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11790 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-05 08:19:17 +00:00
Jean-Philippe Lang
afa9100453 Fixed test broken by r11787 (#13943).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11789 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-04 15:44:09 +00:00
Jean-Philippe Lang
d69de691a7 Fixed that bulk copy raises an error on validation failure (#13943).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11788 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-04 15:18:16 +00:00
Jean-Philippe Lang
70bdb86c53 Preserve field values on bulk edit failure (#13943).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11787 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-04 15:03:07 +00:00
Jean-Philippe Lang
1269e6c7d3 Display the bulk edit form with error messages when some issues can not be saved (#13943).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11786 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-04 08:52:51 +00:00
Jean-Philippe Lang
ed18b3359b Adds a method for extracting MailHandler options from ENV.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11785 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-04 07:32:35 +00:00
Toshi MARUYAMA
33afeea87a use assert_select instead of assert_tag at versions index sidebar
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11784 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-03 11:39:33 +00:00
Toshi MARUYAMA
452c71c9dc use li tags for label completed versions and subproject in version index sidebar (#13242)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11783 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-03 11:39:23 +00:00
Toshi MARUYAMA
42753001ea use li tags for completed versions in version index sidebar (#13242)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11782 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-03 11:39:11 +00:00
Toshi MARUYAMA
8d824f5088 use li tags for versions in version index (#13242)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11781 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-03 09:53:29 +00:00
Toshi MARUYAMA
bee45bac8f remove unneeded h() from versions index tracker name
Rails3 escapes by default.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11780 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-03 09:53:19 +00:00
Toshi MARUYAMA
5aca038b7c use li tags for trackers in version index (#13242)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11779 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-03 09:53:09 +00:00
Toshi MARUYAMA
22a7885605 code layout clean up app/views/versions/index.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11778 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-03 09:52:58 +00:00
Toshi MARUYAMA
7bd4ea835e use li tags for issue links in documents index (#13242)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11777 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-03 08:09:47 +00:00
Toshi MARUYAMA
012dc74eea use li tags for issue links in activities index (#13242)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11776 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-03 08:09:36 +00:00
Toshi MARUYAMA
eb8770899c use li tags for issue links in the wiki sidebar (#13242)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11775 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-03 08:09:26 +00:00
Toshi MARUYAMA
784f33daa7 code layout clean up test/functional/versions_controller_test.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11774 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-03 08:09:16 +00:00
Toshi MARUYAMA
59b1a6695e fix error and inconsistencies in Croatian translation (#13931)
Contributed by Jadranko Stjepanović.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11773 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-03 00:49:40 +00:00
Jean-Baptiste Barth
953e4b4abf Add missing tests for Redmine::MenuManager::Mapper#initialize.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11772 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-03 00:40:41 +00:00
Jean-Baptiste Barth
208d6d881c Add missing tests for Redmine::Helpers::Gantt#number_of_rows.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11771 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-02 23:42:03 +00:00
Jean-Baptiste Barth
bc68c1c039 Add missing unit tests for ApplicationHelper#link_to_if_authorized.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11770 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-02 22:57:24 +00:00
Jean-Baptiste Barth
84e455b583 Remove duplicate test TokenTest#test_find_token_should_return_nil_with_wrong_action.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11768 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-02 18:37:20 +00:00
Jean-Baptiste Barth
e6ab36d205 Remove duplicate test Redmine::I18nTest#test_time_format (keeping the most complete).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11767 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-02 18:14:26 +00:00
Jean-Baptiste Barth
e771d68214 Allow plugins to define their base directory (#13927).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11766 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-02 17:59:34 +00:00
Jean-Baptiste Barth
501007f01d Update URL when changing tab (#13900).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11765 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-02 16:09:58 +00:00
Jean-Baptiste Barth
8aa1bdc031 Add .powrc and .rvmrc in svn, git and hg ignores
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11764 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-02 16:01:31 +00:00
Jean-Philippe Lang
c5ac2d3966 Fixed that deleting a system activity with children in use raises an error (#13783).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11763 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-01 17:10:15 +00:00
Jean-Philippe Lang
6c39a260a3 Propose system activities only when reassigning time entries (#13783).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11762 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-01 16:43:51 +00:00
Jean-Philippe Lang
5cc597e394 Fixed: "obj" parameter is not defined for macros used in description of documents (#13821).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11761 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-01 16:08:51 +00:00
Jean-Philippe Lang
5a3b903733 Fixed: Unable to set custom fields for versions using the REST API (#13850).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11760 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-01 15:57:31 +00:00
Jean-Philippe Lang
92dcaeb472 Updates for 2.3.1 release.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11757 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-01 15:13:58 +00:00
Jean-Philippe Lang
9d190c922a Pevents duplicate accesskeys (#12684).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11754 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-01 13:13:53 +00:00
Jean-Philippe Lang
e1d47931f1 Restores the bottom action menu.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11753 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-01 13:12:53 +00:00
Jean-Philippe Lang
5d09c730d4 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11752 e93f8b46-1217-0410-a6f0-8f06a7374b81 2013-05-01 13:11:49 +00:00
Jean-Philippe Lang
89847f9269 Fixed: Lost text after selection in issue list with IE (#12650).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11750 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-01 12:52:37 +00:00
Jean-Philippe Lang
2ad0465864 Fetching emails via rake task does not support --no-account-notice and --default-group options (#13712).
Contributed by Julian Faude and Alex Shulgin.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11748 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-01 12:28:09 +00:00
Toshi MARUYAMA
f8b756627c code layout clean up application.js
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11744 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-23 04:10:30 +00:00
Toshi MARUYAMA
af7540a23a code layout clean up select_list_move.js
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11743 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-23 04:10:18 +00:00
Toshi MARUYAMA
b54496e61f remove commented code from select_list_move.js
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11742 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-23 04:10:04 +00:00
Toshi MARUYAMA
86442e60ed application.js: randomKey function optimization (#13826)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11741 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-22 08:10:48 +00:00
Toshi MARUYAMA
932380b284 fix favicon bug in IE8 (#13829)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11740 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-22 05:56:15 +00:00
Toshi MARUYAMA
8387c628cd fix JavaScript error of revision_graph.js on IE7 (#13823)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11738 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-21 07:34:38 +00:00
Toshi MARUYAMA
e59814f981 fix JavaScript error of gantt.js on IE7 (#13823)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11737 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-21 07:34:27 +00:00
Toshi MARUYAMA
fe903be480 remove trailing white-space from app/models/project.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11736 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-21 04:56:26 +00:00
Toshi MARUYAMA
885b67fcaa update jquery.ui.datepicker-de.js (#13825)
This is from following revision.
10ca48308f

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11735 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-21 03:50:13 +00:00
Toshi MARUYAMA
22a69cc9ae add missing ; in {} at application.js (#13811)
Contributed by Adrian Wilkins.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11733 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-20 08:08:28 +00:00
Toshi MARUYAMA
de26e3fb85 fix ; position of if(){} at application.js (#13811)
Contributed by Adrian Wilkins.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11732 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-20 08:08:17 +00:00
Toshi MARUYAMA
485ce41523 remove unneeded ; from warnLeavingUnsaved of application.js (#13811)
Contributed by Adrian Wilkins.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11731 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-20 08:08:05 +00:00
Toshi MARUYAMA
98bb49382b add missing ; at toggleCheckboxesBySelector of application.js (#13811)
Contributed by Adrian Wilkins.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11730 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-20 08:07:54 +00:00
Toshi MARUYAMA
b31d1329ca use ===/!== instead of ==/!= in application.js (#13811)
Contributed by Adrian Wilkins.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11729 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-20 08:07:41 +00:00
Toshi MARUYAMA
f7f6b7ba5b fix JavaScript error on IE7 (#13811)
Contributed by Adrian Wilkins.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11728 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-20 07:39:26 +00:00
Toshi MARUYAMA
eae3a82067 Bulgarian "label_statistics" translation changed by Ivan Cenov (#13808)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11727 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-19 07:18:50 +00:00
Toshi MARUYAMA
7ab18f6aa1 remove trailing white-spaces and redundant empty line from app/models/issue_query.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11726 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-19 07:18:38 +00:00
Toshi MARUYAMA
6c182d0a8a remove unused variable from QueriesHelperTest
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11725 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-19 07:18:26 +00:00
Toshi MARUYAMA
21b1783da3 add TODO comment about gantt issues sort (#7335)
Sorting by date was dropped by r4581 (#7128).

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11724 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-19 05:14:25 +00:00
Toshi MARUYAMA
ba11020fdf make height of "Commits per author" graph flexible (#1983, #13486)
Contributed by Max Horn.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11723 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-18 02:07:44 +00:00
Toshi MARUYAMA
1bdd37f3e0 fix test name (#13482)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11722 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-18 01:09:06 +00:00
Toshi MARUYAMA
19f70c95d1 not add empty header/footer to notification emails (#13482)
Contributed by Max Horn.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11721 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-18 00:58:24 +00:00
Toshi MARUYAMA
9fea2ab6d2 add mail footer test (#13482)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11720 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-18 00:29:29 +00:00
Toshi MARUYAMA
c709c5120c extend mail header test to text mail (#13482)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11719 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-18 00:29:18 +00:00
Toshi MARUYAMA
32ee6b3275 stricter asserting of subversion url validation test
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11718 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-14 16:18:45 +00:00
Toshi MARUYAMA
7a18920728 add unit tests of subversion url validation
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11717 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-14 15:31:18 +00:00
Toshi MARUYAMA
5d05de4b09 code layout clean up test/unit/repository_subversion_test.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11716 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-14 15:31:04 +00:00
Toshi MARUYAMA
36120d17e7 remove trailing white-space from app/models/role.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11715 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-12 01:50:01 +00:00
Toshi MARUYAMA
691add1aff remove redundant 'IssuesHelper#' from issues_helper_test context
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11714 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-12 01:18:52 +00:00
Toshi MARUYAMA
c745acf4c2 code layout clean up issues_helper_test.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11713 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-12 01:18:40 +00:00
Toshi MARUYAMA
6869e652c4 remove redundant variable from config/initializers/00-core_plugins.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11712 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-12 01:18:28 +00:00
Toshi MARUYAMA
bd0e728352 fix favicon for Opera (#13687)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11711 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-06 15:05:03 +00:00
Toshi MARUYAMA
760d397363 svn propset svn:eol-style native test fixtures (#13644)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11708 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-05 07:38:02 +00:00
Toshi MARUYAMA
6469e9a5a3 fix diff error in case of line_left out of range (#13644)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11707 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-05 07:30:51 +00:00
Toshi MARUYAMA
0d02931759 check integer ordinal range on only Ruby 1.8 (#13644)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11706 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-05 05:51:58 +00:00
Toshi MARUYAMA
ed0a8413a2 remove extra white-spaces around new-line from Lithuanian translation
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11705 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-04 12:54:17 +00:00
Toshi MARUYAMA
d42c3dbf18 remove trailing white-spaces from Lithuanian translation
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11704 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-04 12:54:06 +00:00
Toshi MARUYAMA
09d1f5dd2e Lithuanian translation changed by Vasaris Vėjas (#13674)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11701 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-04 12:01:03 +00:00
Toshi MARUYAMA
d5004b607b Lithuanian translation for 2.3-stable updated by Vasaris Vėjas (#13678, #13674)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11700 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-04 11:25:43 +00:00
Toshi MARUYAMA
c961fe8f2b remove duplicate "text_repository_usernames_mapping" from Lithuanian translation
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11699 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-04 10:12:15 +00:00
Jean-Philippe Lang
633e4a00e6 Check that the SCM log file is writable before using it (#13541).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11698 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-03 20:01:41 +00:00
Jean-Philippe Lang
25209273d3 Fixed that CSV Export of Spent Time ignores filters and columns selection (#13618).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11696 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-03 16:48:28 +00:00
Etienne Massip
4224a0c3fe Code cleanup (#13630).
Contributed by F Schroedter.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11694 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-02 17:37:52 +00:00
Etienne Massip
4a3864a180 Fixed that issue list PDF export displays ID column twice (#13630).
Contributed by F Schroedter.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11693 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-04-02 17:34:15 +00:00
Jean-Philippe Lang
ed5b14884c Fixed that r11641 prevents precedes/follows relations between subtasks (#13586).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11692 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-26 21:31:29 +00:00
Toshi MARUYAMA
de68231632 remove trailing white-space from app/models/setting.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11688 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-25 13:39:56 +00:00
Toshi MARUYAMA
bc555048a5 svn:eol-style native jquery.ui.datepicker-pt.js (#13584)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11687 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-25 12:15:43 +00:00
Toshi MARUYAMA
8045ef9d3d add missing Portuguese jQuery UI date picker (#13584)
jquery.ui.datepicker-pt.js is from
https://raw.github.com/jquery/jquery-ui/49f9b849b9c5023f13/ui/i18n/jquery.ui.datepicker-pt.js

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11686 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-25 12:12:28 +00:00
Toshi MARUYAMA
213e8facee add test of datepicker in Simplified Chinese and Traditional Chinese (#13579)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11685 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-25 11:46:41 +00:00
Toshi MARUYAMA
3f2982ede6 back out r11683.
explicitly define jquery locale in en en-GB pt pt-BR.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11684 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-25 11:46:30 +00:00
Toshi MARUYAMA
1ef354f75c explicitly define jquery locale in en en-GB pt pt-BR
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11683 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-25 10:41:13 +00:00
Toshi MARUYAMA
2adc469439 fix that datepicker uses Simplified Chinese in Traditional Chinese locale (#13579)
Contributed by Chage Juan.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11682 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-25 10:41:02 +00:00
Toshi MARUYAMA
1b9faa1aaf Japanese translation improvement ("done ratio") by Go MAEDA (#13577)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11681 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-25 08:11:50 +00:00
Jean-Philippe Lang
d8769cb27c Log SCM stderr when log level is set to debug only (#13541).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11680 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-22 07:50:28 +00:00
Toshi MARUYAMA
c20a13f8ee Dutch translation changed by Pieter Nicolai (#13551)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11677 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-22 00:34:47 +00:00
Toshi MARUYAMA
3f277b6b65 Dutch translation for trunk updated by Pieter Nicolai (#13551)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11676 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-22 00:34:36 +00:00
Toshi MARUYAMA
700e9c8aa0 Dutch translations for 2.3-stable updated by Pieter Nicolai (#13552, #13551)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11675 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-21 23:40:32 +00:00
Toshi MARUYAMA
919d4589b9 fix unit search test failure (#13405)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11674 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-21 23:40:21 +00:00
Toshi MARUYAMA
1e5fa50a80 add test to ensure language name is UTF-8 (#12475)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11673 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-21 22:54:59 +00:00
Toshi MARUYAMA
31590e307a fix test failure (#13405)
<pre>
  1) Failure:
test_scan_changesets_for_issue_ids(RepositoryTest) [/xxx/test/unit/repository_test.rb:214]:
<"Applied in changeset r2."> expected but was
<"Applied in changeset commit:691322a8eb01e11fd7.">.
</pre>

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11672 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-21 22:54:48 +00:00
Etienne Massip
d7cb14773b Fixed commit link title escaping (fixes #13405).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11671 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-21 21:53:28 +00:00
Toshi MARUYAMA
b26f1c55cc remove trailing white-space from app/models/user_preference.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11670 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-20 08:48:03 +00:00
Toshi MARUYAMA
75050f767a Traditional Chinese "label_total_time" translation changed by ChunChang Lo (#13528)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11668 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-20 06:02:58 +00:00
Toshi MARUYAMA
8cbd91214d code layout cleanup test/integration/account_test.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11667 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-20 06:02:48 +00:00
Toshi MARUYAMA
a9ea20e818 backout r11665 (#13528)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11666 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-20 05:03:51 +00:00
Toshi MARUYAMA
b3c5ef8afe Traditional Chinese "label_total_time" translation changed by ChunChang Lo (#13528)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11665 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-20 04:43:51 +00:00
Toshi MARUYAMA
9c1f943a17 Traditional Chinese translation for 2.3-stable updated by ChunChang Lo (#13531 ,#13528)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11664 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-20 04:43:41 +00:00
Jean-Philippe Lang
6bc4a110e4 JQuery Datepicker popup is missing multiple month/year modifiers (#13260).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11663 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-19 21:53:22 +00:00
Jean-Philippe Lang
064bb49b55 Add a "Cancel" button to the "Delete" project page when deleting a project (#2795).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11662 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-19 21:19:46 +00:00
Jean-Philippe Lang
067aebab76 Updates for 2.3.0 release.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11657 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-19 19:22:22 +00:00
Jean-Philippe Lang
aa583b4144 All translations: RSS -> Atom (#13460).
Patch by Daniel Felix.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11654 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-19 18:26:32 +00:00
Toshi MARUYAMA
32391269ae remove trailing white space from app/models/version.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11651 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-19 07:29:00 +00:00
Toshi MARUYAMA
cc5f59abd4 fix broken tests on Rails 3.2.13 with Ruby 1.8 (#12399, #12375)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11650 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-19 06:35:39 +00:00
Toshi MARUYAMA
cf1cc08c49 upgrade Rails 3.2.13
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11649 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-19 05:23:52 +00:00
Toshi MARUYAMA
e41b90c71c upgrade mocha ~> 0.13.3
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11648 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-19 03:28:13 +00:00
Toshi MARUYAMA
134aeb2ca8 backout r11644.
revert Rails version to 3.2.12.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11647 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-19 03:28:03 +00:00
Toshi MARUYAMA
c616f21d1f fix pt-BR "permission_set_notes_private" translation (#13514)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11645 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-19 02:46:40 +00:00
Toshi MARUYAMA
b8a70f2e24 upgrade Rails 3.2.13
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11644 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-19 02:27:16 +00:00
Toshi MARUYAMA
5d600587a1 replace tab to space at app/models/mail_handler.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11643 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-18 02:14:11 +00:00
Jean-Philippe Lang
24e99f8b22 Code cleanup.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11642 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-17 15:17:48 +00:00
Jean-Philippe Lang
38b3e045cf Fixed: Circular loop when using relations and subtasks (#8794).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11641 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-17 15:02:57 +00:00
Jean-Philippe Lang
b1afd75620 Fixed: subtasks don't resepect following/precedes relations on creation (#12968).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11640 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-17 13:46:20 +00:00
Toshi MARUYAMA
628f9dc4cf PDF: fix incompatible character encodings: UTF-8 and ASCII-8BIT (#13354)
Contributed by Jun NAITOH.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11637 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-16 07:02:43 +00:00
Toshi MARUYAMA
7040a1212f replace tabs to spaces at app/views/repositories/_navigation.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11636 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-15 14:58:22 +00:00
Toshi MARUYAMA
1ada210da1 replace tabs to spaces at app/views/projects/settings/_issue_categories.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11635 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-15 14:58:11 +00:00
Toshi MARUYAMA
1dc94c65cb replace tabs to spaces at app/views/projects/settings/_boards.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11634 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-15 14:58:00 +00:00
Toshi MARUYAMA
3749e4eb98 replace tabs to spaces and code cleanup at app/views/repositories/_form.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11633 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-15 14:57:49 +00:00
Toshi MARUYAMA
544bbba046 replace tabs to spaces and code cleanup at app/views/issues/bulk_edit.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11632 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-15 14:57:38 +00:00
Toshi MARUYAMA
a97a2fec3f replace tabs to spaces and code cleanup at app/views/versions/_overview.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11631 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-15 14:15:57 +00:00
Toshi MARUYAMA
4e62001154 replace tabs to spaces at app/views/versions/index.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11630 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-15 14:15:46 +00:00
Toshi MARUYAMA
ab9f201302 replace tabs to spaces at app/views/documents/index.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11629 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-15 14:15:34 +00:00
Toshi MARUYAMA
a1b24e0f65 remove trailing tabs from app/views/context_menus/issues.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11628 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-15 13:12:04 +00:00
Toshi MARUYAMA
eaa016bbc3 replace tabs to spaces and fix indents at app/views/my/destroy.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11627 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-15 11:30:36 +00:00
Toshi MARUYAMA
e6f7e47547 update .gitignore for non-default themes + plugins (#13476)
Contributed by Pieter Nicolai.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11626 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-15 10:51:35 +00:00
Toshi MARUYAMA
d78d83f553 replace tabs to spaces and fix indents at app/views/settings/_repositories.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11625 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-15 10:51:24 +00:00
Toshi MARUYAMA
1f4e3af192 replace tabs to spaces at app/views/settings/_issues.html.erb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11624 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-15 10:51:13 +00:00
Toshi MARUYAMA
e74734f57c fix pt-BR translation (#13475)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11622 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-15 00:58:42 +00:00
Toshi MARUYAMA
71b3b5d1b5 Russian translation updated by Kirill Bezrukov (#13463)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11620 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-13 08:00:41 +00:00
Toshi MARUYAMA
51631e54f8 Bulgarian translation ordered by Ivan Cenov (#13458)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11615 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-12 23:46:32 +00:00
Toshi MARUYAMA
0dac2e8c59 Czech translation changed by Karel Pičman (#13450)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11614 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-12 23:46:22 +00:00
Toshi MARUYAMA
c950adfe82 Fixing HTML in groups index view
Contributed by Gregor Schmidt.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11613 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-12 23:17:16 +00:00
Jean-Philippe Lang
61396f68d0 Use #count instead of #size.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11612 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-12 20:44:25 +00:00
Jean-Philippe Lang
1d48ab201b Log errors when bulk edit/copy fails (#13440).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11611 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-12 19:43:46 +00:00
Jean-Philippe Lang
83d7761998 Always instanciate a relation.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11610 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-12 18:35:59 +00:00
Jean-Philippe Lang
6d20cfe831 Moves Project#users to a regular method.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11609 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-12 18:32:36 +00:00
Jean-Philippe Lang
3528343863 Moves Project#principals to a regular method.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11608 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-12 18:07:37 +00:00
Jean-Philippe Lang
248d983a7d Don't verify method.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11607 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-12 17:25:49 +00:00
Jean-Philippe Lang
447e15d6cb Prevent one query per User#member_of? call after r11508 (#13301).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11605 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-12 17:08:50 +00:00
Toshi MARUYAMA
734188c0dc German translation changed by Filou Centrinov (#13447)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11603 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-12 14:37:21 +00:00
Toshi MARUYAMA
999c9762e6 replace English setting_emails_header and setting_emails_header translation (#13438)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11601 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-12 11:54:34 +00:00
Toshi MARUYAMA
5e4060b15c replace scm to SCM at config/configuration.yml.example (#13438)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11600 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-12 11:54:23 +00:00
Toshi MARUYAMA
121df3d4a7 replace scm to SCM at locale files (#13438)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11599 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-12 11:54:11 +00:00
Toshi MARUYAMA
f83c0a81fe German translation of setting_emails_header changed by Filou Centrinov (#13437)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11597 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-12 10:35:00 +00:00
Jean-Philippe Lang
de6e4ad431 INSTALL update (#12913).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11592 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-11 18:12:42 +00:00
Jean-Philippe Lang
bca9a8431e Mail handler: set mail_notification to only_my_events when creating a new user (#13341).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11590 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-11 17:50:18 +00:00
Toshi MARUYAMA
7cecd72faa Korean translation changed by Jongwook Choi (#13420)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11588 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-11 00:47:24 +00:00
Toshi MARUYAMA
d85cc5f561 Korean translation updated by Jongwook Choi (#13420)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11585 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-10 22:52:09 +00:00
Toshi MARUYAMA
fe8fb875c2 Korean translation changed by Jongwook Choi (#13420)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11584 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-10 22:51:58 +00:00
Jean-Philippe Lang
06a92fe0d0 Adds label_total_time string (#13337).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11582 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-10 13:01:46 +00:00
Toshi MARUYAMA
3126ff8388 Bulgarian translation updated and changed by Ivan Cenov (#13414)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11578 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-10 03:50:41 +00:00
Jean-Philippe Lang
9c2561b59d Preserve gantt options when changing filters (#12122).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11571 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-09 10:44:39 +00:00
Jean-Philippe Lang
bb80baf9a5 Adds setting_default_projects_tracker_ids string to locales (#13175, #13272).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11567 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-09 09:52:35 +00:00
Toshi MARUYAMA
ba797909b0 Korean translation changed by Lucas Yang (#13399)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11560 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-08 08:10:29 +00:00
Toshi MARUYAMA
5416c6e3ef Czech translation changed by Karel Pičman (#13391)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11556 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-07 23:13:35 +00:00
Toshi MARUYAMA
9d406189bd Czech translation for trunk updated by Karel Pičman (#13391)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11555 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-07 23:13:24 +00:00
Toshi MARUYAMA
df3adb9a90 Czech translation for 2.3-stable updated by Karel Pičman (#13391)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11554 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-07 23:13:13 +00:00
Toshi MARUYAMA
d40ad599ed Czech translation for 2.2-stable updated by Karel Pičman (#13398, #13391)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11553 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-07 23:13:02 +00:00
Toshi MARUYAMA
dac066ea0a svn propset svn:eol-style native to fixtures (#12641)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11550 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-07 12:53:36 +00:00
Toshi MARUYAMA
d3de07a17c fix that diff outputs become ??? in some non ASCII words (#12641)
Contributed by Filou Centrinov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11549 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-07 10:36:06 +00:00
Toshi MARUYAMA
72539451aa set html encoding utf8 at Diff class (#12641)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11547 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-07 10:17:45 +00:00
Toshi MARUYAMA
0d141eef32 code cleanup (#12641)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11546 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-07 08:47:38 +00:00
Toshi MARUYAMA
b19a6d06d9 move utf8 encoding from view to UnifiedDiff (#12641)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11545 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-07 08:31:58 +00:00
Toshi MARUYAMA
8e92ffc191 remove unnecessary h() from diff filename (#12641)
On Rails3, escaping is default.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11544 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-07 07:24:46 +00:00
Toshi MARUYAMA
b53b7b1acd use %r{} instead of // at app/models/repository/subversion.rb
Syntax highlight is broken in gedit 2.28.4 on CentOS 6.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11543 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-07 04:07:20 +00:00
Toshi MARUYAMA
39b9599360 use %r{} instead of // at lib/redmine/unified_diff.rb
Syntax highlight is broken in gedit 2.28.4 on CentOS 6.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11542 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-07 04:07:09 +00:00
Toshi MARUYAMA
5984adc3df code layout cleanup AccountController#open_id_authenticate
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11539 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-06 08:42:00 +00:00
Toshi MARUYAMA
6a4966fe10 remove trailing white-spaces from test/functional/account_controller_openid_test.rb
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11538 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-06 08:41:48 +00:00
Toshi MARUYAMA
419b18b4a9 fix some Japanese "issue" translations (#13350)
Contributed by Go MAEDA.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11537 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-06 08:41:36 +00:00
Toshi MARUYAMA
7d3f29ea3f Japanese translation updated by Go MAEDA (#13349)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11536 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-06 08:41:25 +00:00
Toshi MARUYAMA
9286ddd655 Vietnamese translation changed by Minh Thien Nguyen (#13339)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11530 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-03 10:26:26 +00:00
Toshi MARUYAMA
3357850013 Vietnamese translation for 2.3-stable updated by Minh Thien Nguyen (#13339)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11529 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-03 10:26:14 +00:00
Toshi MARUYAMA
68e98fa37d Vietnamese translation for 2.2-stable updated by Minh Thien Nguyen (#13343, #13339)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11528 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-03 10:26:01 +00:00
Toshi MARUYAMA
0225030551 Ruby2.0: remove "warning: class variable access from toplevel" in lib/plugins/rfpdf/lib/tcpdf.rb (#13338, #13329)
Contributed by Jun NAITOH.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11527 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-03 10:25:47 +00:00
Jean-Philippe Lang
f77ed4a7c3 Mail handler: adds --no-notification option to disable notifications to the created user (#13341).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11526 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-03 08:57:00 +00:00
Jean-Philippe Lang
6cffab9919 Mail handler: adds --no-account-notice option for not sending account information to the created user (#11498).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11525 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-03 08:41:52 +00:00
Jean-Philippe Lang
e7bf31d162 Typo and text formatting in rdm-mailhandler usage.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11524 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-03 08:10:40 +00:00
Jean-Philippe Lang
c4cf97dea5 Adds copyright.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11523 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-03 08:05:44 +00:00
Jean-Philippe Lang
b25d496c24 Mail handler: adds --default-group option to add created user to one or more groups (#13340).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11522 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-03 07:59:29 +00:00
Jean-Philippe Lang
d5ca514688 Adds autologin param in openid return_to url (#3371).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11521 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-02 20:38:25 +00:00
Jean-Philippe Lang
a010372458 Fixed that autologin cookie is not deleted when using custom cookie name (#13335).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11520 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-02 20:30:57 +00:00
Jean-Philippe Lang
08ef201cec Fixed that autologin is broken when using a custom cookie name (#13335).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11519 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-02 20:28:21 +00:00
Jean-Philippe Lang
80807a8c49 Add user's API key to /users/current.format (#8529).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11518 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-01 16:32:30 +00:00
Jean-Philippe Lang
caf61dc923 Fixed that copying an issue as a child of itself creates an extra issue (#13328).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11513 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-01 12:26:06 +00:00
Jean-Philippe Lang
4185a4ae3b Test failures (#13309).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11512 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-01 11:27:55 +00:00
Jean-Philippe Lang
5a8b369754 Project select for new membership overflows with long project names.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11511 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-01 11:01:28 +00:00
Jean-Philippe Lang
cfcc9069e5 Performance: avoid one "SELECT 1 ..." query per project on user memberships form.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11510 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-01 10:54:31 +00:00
Jean-Philippe Lang
a140a03a35 Adds "tracker-[id]" CSS class to issues (#13309).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11509 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-01 10:42:05 +00:00
Jean-Philippe Lang
6803d95a32 Performance: avoid querying all memberships in User#roles_for_project (#13301).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11508 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-01 10:24:23 +00:00
Jean-Philippe Lang
69657be534 Test failure with ruby 2.0.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11507 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-01 09:01:05 +00:00
Jean-Philippe Lang
5f0509435a Regexp not working as expected with ruby 2.0.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11506 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-01 08:57:01 +00:00
Toshi MARUYAMA
b2f2c58f3d pt-BR translation changed (#13324)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11504 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-01 03:33:17 +00:00
Toshi MARUYAMA
466a7f2293 pt-BR translation for trunk updated (#13324)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11502 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-01 02:10:24 +00:00
Toshi MARUYAMA
5f4e940a09 pt-BR translation for 2.3-stable updated (#13324)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11499 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-01 00:48:11 +00:00
Toshi MARUYAMA
2f9c6b38cd pt-BR translation for 2.2-stable updated (#13325, #13324)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11498 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-03-01 00:13:51 +00:00
Jean-Philippe Lang
5c1e1ee4bb Fixed that #reload raises a Stack too deep error with ruby 2.0.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11497 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-28 18:47:25 +00:00
Jean-Philippe Lang
f544dd682b Code cleanup.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11496 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-28 17:52:29 +00:00
Jean-Philippe Lang
5bf647f290 Don't reload the issue in after_save callback.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11495 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-28 17:47:58 +00:00
Jean-Philippe Lang
953b3619d4 Distinguish mysql/mysql2 adapters in Gemfile (#13270).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11494 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-28 17:20:28 +00:00
Toshi MARUYAMA
a5c05435ab pt-BR "label_last_n_weeks" translation updated (#13310)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11491 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-28 07:22:01 +00:00
Toshi MARUYAMA
9a8f430db6 Ruby2.0: switch mysql2 platforms by RUBY_VERSION
It seems old bundler does not support :mri_20 and :mingw_20

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11490 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-26 12:20:45 +00:00
Toshi MARUYAMA
23941adee1 Ruby2.0: add platforms to Gemfile mysql2
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11489 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-26 11:41:20 +00:00
Toshi MARUYAMA
bf917a61e7 Ruby2.0: add "require 'yaml'" to Gemfile
On ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-linux]:
<pre>
$ ruby script/about
There was an error in your Gemfile, and Bundler cannot continue.
</pre>

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11488 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-26 11:41:09 +00:00
Toshi MARUYAMA
2ffbfacf5f back out r11486
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11487 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-26 11:40:58 +00:00
Jean-Philippe Lang
3f67ec4436 Require 'yaml'.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11486 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-25 17:31:58 +00:00
Toshi MARUYAMA
36da6d0f80 Russian translation updated by Kirill Bezrukov (#13281)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11483 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-25 14:22:24 +00:00
Toshi MARUYAMA
7d49d8b20e German translation changed by Filou Centrinov (#13280)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11482 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-25 13:41:16 +00:00
Toshi MARUYAMA
fb0303ac1d Traditional Chinese translation updated by ChunChang Lo (#13279)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11480 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-25 10:50:20 +00:00
Toshi MARUYAMA
223f892742 Russian translation updated by Filou Centrinov (#13266)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11479 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-25 10:50:09 +00:00
Toshi MARUYAMA
b32056b79d German translation updated by Filou Centrinov (#13265)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11478 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-25 10:49:58 +00:00
Toshi MARUYAMA
92532fb7b8 Bulgarian translation updated by Ivan Cenov (#13264)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11477 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-25 10:49:47 +00:00
Toshi MARUYAMA
c22810ed51 German translation changed by Filou Centrinov (#13246)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11476 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-25 10:33:01 +00:00
Jean-Philippe Lang
870d9bad86 Removed deferred test, circular relations are unit tested.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11475 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-24 13:03:00 +00:00
Jean-Philippe Lang
5b4a9ac3b3 Restricts characters before auto links (#10277).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11474 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-24 12:56:50 +00:00
Jean-Philippe Lang
dfca67d844 Fixed that www followed by a dot generates broken links in formatted text (#3676).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11473 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-24 12:39:06 +00:00
Jean-Philippe Lang
458800c1d5 Time entry with 2 digits year should not validate (#3107).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11472 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-24 12:28:44 +00:00
Jean-Philippe Lang
0a6a7f0ed7 Fixed that time entries report by week breaks on edge cases (#5329).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11471 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-24 12:18:29 +00:00
Jean-Philippe Lang
e37ee0d21b Use li tags for issue links in the sidebar (#13242).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11470 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-24 11:33:27 +00:00
Jean-Philippe Lang
de716bd024 Code cleanup.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11469 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-24 11:25:52 +00:00
Jean-Philippe Lang
cd9de0837f Code cleanup.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11468 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-24 11:10:12 +00:00
Jean-Philippe Lang
0082e36b60 Code cleanup.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11467 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-24 11:08:14 +00:00
Jean-Philippe Lang
ace19cc20f Use ti tags for sidebar queries (#13242).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11466 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-24 11:06:08 +00:00
Jean-Philippe Lang
0cefb7716e Use https://rubygems.org as gem source (#13173).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11464 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-24 10:13:43 +00:00
Jean-Philippe Lang
6f21796c34 Missing fixtures.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11462 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-24 10:05:58 +00:00
Jean-Philippe Lang
8e17c2aeac Fixed that relations may not be refreshed when adding a follows relation (#13251).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11461 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-24 09:59:45 +00:00
Jean-Philippe Lang
85b872f340 Makes project custom fields available on spent time report (#1766).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11459 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-24 08:57:04 +00:00
Jean-Philippe Lang
3269fab34e Adds field_generate_password string to locales (#3872).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11458 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-23 17:00:53 +00:00
Jean-Philippe Lang
e14caf8e33 Use User#generate_password in MailHandler.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11457 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-23 16:57:45 +00:00
Jean-Philippe Lang
fac4a79d4c Option to generate a random password on user creation/update.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11456 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-23 16:50:07 +00:00
552 changed files with 25788 additions and 5100 deletions

8
.gitignore vendored
View File

@@ -1,5 +1,7 @@
/.project
/.loadpath
/.powrc
/.rvmrc
/config/additional_environment.rb
/config/configuration.yml
/config/database.yml
@@ -15,8 +17,14 @@
/lib/redmine/scm/adapters/mercurial/redminehelper.pyo
/log/*.log*
/log/mongrel_debug
/plugins/*
!/plugins/README
/public/dispatch.*
/public/plugin_assets
/public/themes/*
!/public/themes/alternate
!/public/themes/classic
!/public/themes/README
/tmp/*
/tmp/cache/*
/tmp/pdf/*

View File

@@ -2,6 +2,8 @@ syntax: glob
.project
.loadpath
.powrc
.rvmrc
config/additional_environment.rb
config/configuration.yml
config/database.yml

8
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,8 @@
**Do not send a pull requst to this github repository**.
For more detail, please see [official website] wiki [Contribute].
[official website]: http://www.redmine.org
[Contribute]: http://www.redmine.org/projects/redmine/wiki/Contribute

17
Gemfile
View File

@@ -3,7 +3,7 @@ source 'https://rubygems.org'
gem "rails", "3.2.13"
gem "jquery-rails", "~> 2.0.2"
gem "i18n", "~> 0.6.0"
gem "coderay", "~> 1.0.6"
gem "coderay", "~> 1.1.0"
gem "fastercsv", "~> 1.5.0", :platforms => [:mri_18, :mingw_18, :jruby]
gem "builder", "3.0.0"
@@ -14,7 +14,7 @@ end
# Optional gem for OpenID authentication
group :openid do
gem "ruby-openid", "~> 2.1.4", :require => "openid"
gem "ruby-openid", "~> 2.3.0", :require => "openid"
gem "rack-openid"
end
@@ -31,7 +31,7 @@ end
platforms :jruby do
# jruby-openssl is bundled with JRuby 1.7.0
gem "jruby-openssl" if Object.const_defined?(:JRUBY_VERSION) && JRUBY_VERSION < '1.7.0'
gem "activerecord-jdbc-adapter", "1.2.5"
gem "activerecord-jdbc-adapter", "~> 1.2.6"
end
# Include database gems for the adapters found in the database
@@ -78,8 +78,12 @@ end
group :test do
gem "shoulda", "~> 3.3.2"
gem "mocha", "~> 0.13.3"
gem 'capybara', '~> 2.0.0'
gem "mocha", ">= 0.14", :require => 'mocha/api'
if RUBY_VERSION >= '1.9.3'
gem "capybara", "~> 2.1.0"
gem "selenium-webdriver"
gem "database_cleaner"
end
end
local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local")
@@ -91,5 +95,6 @@ end
# Load plugins' Gemfiles
Dir.glob File.expand_path("../plugins/*/Gemfile", __FILE__) do |file|
puts "Loading #{file} ..." if $DEBUG # `ruby -d` or `bundle -v`
instance_eval File.read(file)
#TODO: switch to "eval_gemfile file" when bundler >= 1.2.0 will be required (rails 4)
instance_eval File.read(file), file
end

View File

@@ -20,7 +20,7 @@ class AccountController < ApplicationController
include CustomFieldsHelper
# prevents login action to be filtered by check_if_login_required application scope filter
skip_before_filter :check_if_login_required
skip_before_filter :check_if_login_required, :check_password_change
# Login request and validation
def login
@@ -75,11 +75,15 @@ class AccountController < ApplicationController
else
if request.post?
user = User.find_by_mail(params[:mail].to_s)
# user not found or not active
unless user && user.active?
# user not found
unless user
flash.now[:error] = l(:notice_account_unknown_email)
return
end
unless user.active?
handle_inactive_user(user, lost_password_path)
return
end
# user cannot change its password
unless user.change_password_allowed?
flash.now[:error] = l(:notice_can_t_change_password)
@@ -152,6 +156,19 @@ class AccountController < ApplicationController
redirect_to signin_path
end
# Sends a new account activation email
def activation_email
if session[:registered_user_id] && Setting.self_registration == '1'
user_id = session.delete(:registered_user_id).to_i
user = User.find_by_id(user_id)
if user && user.registered?
register_by_email_activation(user)
return
end
end
redirect_to(home_url)
end
private
def authenticate_user
@@ -163,7 +180,7 @@ class AccountController < ApplicationController
end
def password_authentication
user = User.try_to_login(params[:username], params[:password])
user = User.try_to_login(params[:username], params[:password], false)
if user.nil?
invalid_credentials
@@ -171,27 +188,31 @@ class AccountController < ApplicationController
onthefly_creation_failed(user, {:login => user.login, :auth_source_id => user.auth_source_id })
else
# Valid user
successful_authentication(user)
if user.active?
successful_authentication(user)
else
handle_inactive_user(user)
end
end
end
def open_id_authenticate(openid_url)
back_url = signin_url(:autologin => params[:autologin])
authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => back_url, :method => :post) do |result, identity_url, registration|
authenticate_with_open_id(
openid_url, :required => [:nickname, :fullname, :email],
:return_to => back_url, :method => :post
) do |result, identity_url, registration|
if result.successful?
user = User.find_or_initialize_by_identity_url(identity_url)
if user.new_record?
# Self-registration off
(redirect_to(home_url); return) unless Setting.self_registration?
# Create on the fly
user.login = registration['nickname'] unless registration['nickname'].nil?
user.mail = registration['email'] unless registration['email'].nil?
user.firstname, user.lastname = registration['fullname'].split(' ') unless registration['fullname'].nil?
user.random_password
user.register
case Setting.self_registration
when '1'
register_by_email_activation(user) do
@@ -211,7 +232,7 @@ class AccountController < ApplicationController
if user.active?
successful_authentication(user)
else
account_pending
handle_inactive_user(user)
end
end
end
@@ -261,7 +282,7 @@ class AccountController < ApplicationController
token = Token.new(:user => user, :action => "register")
if user.save and token.save
Mailer.register(token).deliver
flash[:notice] = l(:notice_account_register_done)
flash[:notice] = l(:notice_account_register_done, :email => user.mail)
redirect_to signin_path
else
yield if block_given?
@@ -291,14 +312,32 @@ class AccountController < ApplicationController
if user.save
# Sends an email to the administrators
Mailer.account_activation_request(user).deliver
account_pending
account_pending(user)
else
yield if block_given?
end
end
def account_pending
flash[:notice] = l(:notice_account_pending)
redirect_to signin_path
def handle_inactive_user(user, redirect_path=signin_path)
if user.registered?
account_pending(user, redirect_path)
else
account_locked(user, redirect_path)
end
end
def account_pending(user, redirect_path=signin_path)
if Setting.self_registration == '1'
flash[:error] = l(:notice_account_not_activated_yet, :url => activation_email_path)
session[:registered_user_id] = user.id
else
flash[:error] = l(:notice_account_pending)
end
redirect_to redirect_path
end
def account_locked(user, redirect_path=signin_path)
flash[:error] = l(:notice_account_locked)
redirect_to redirect_path
end
end

View File

@@ -65,7 +65,7 @@ class AdminController < ApplicationController
@test = Mailer.test_email(User.current).deliver
flash[:notice] = l(:notice_email_sent, User.current.mail)
rescue Exception => e
flash[:error] = l(:notice_email_error, e.message)
flash[:error] = l(:notice_email_error, Redmine::CodesetUtil.replace_invalid_utf8(e.message))
end
ActionMailer::Base.raise_delivery_errors = raise_delivery_errors
redirect_to settings_path(:tab => 'notifications')

View File

@@ -38,7 +38,7 @@ class ApplicationController < ActionController::Base
cookies.delete(autologin_cookie_name)
end
before_filter :session_expiration, :user_setup, :check_if_login_required, :set_localization
before_filter :session_expiration, :user_setup, :check_if_login_required, :check_password_change, :set_localization
rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token
rescue_from ::Unauthorized, :with => :deny_access
@@ -78,6 +78,9 @@ class ApplicationController < ActionController::Base
session[:user_id] = user.id
session[:ctime] = Time.now.utc.to_i
session[:atime] = Time.now.utc.to_i
if user.must_change_password?
session[:pwd] = '1'
end
end
def user_setup
@@ -112,6 +115,10 @@ class ApplicationController < ActionController::Base
authenticate_with_http_basic do |username, password|
user = User.try_to_login(username, password) || User.find_by_api_key(username)
end
if user && user.must_change_password?
render_error :message => 'You must change your password', :status => 403
return
end
end
# Switch user if requested by an admin user
if user && user.admin? && (username = api_switch_user_from_request)
@@ -170,6 +177,16 @@ class ApplicationController < ActionController::Base
require_login if Setting.login_required?
end
def check_password_change
if session[:pwd]
if User.current.must_change_password?
redirect_to my_password_path
else
session.delete(:pwd)
end
end
end
def set_localization
lang = nil
if User.current.logged?
@@ -195,7 +212,13 @@ class ApplicationController < ActionController::Base
url = url_for(:controller => params[:controller], :action => params[:action], :id => params[:id], :project_id => params[:project_id])
end
respond_to do |format|
format.html { redirect_to :controller => "account", :action => "login", :back_url => url }
format.html {
if request.xhr?
head :unauthorized
else
redirect_to :controller => "account", :action => "login", :back_url => url
end
}
format.atom { redirect_to :controller => "account", :action => "login", :back_url => url }
format.xml { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' }
format.js { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' }
@@ -298,7 +321,7 @@ class ApplicationController < ActionController::Base
# Find issues with a single :id param or :ids array param
# Raises a Unauthorized exception if one of the issues is not visible
def find_issues
@issues = Issue.find_all_by_id(params[:id] || params[:ids])
@issues = Issue.where(:id => (params[:id] || params[:ids])).preload(:project, :status, :tracker, :priority, :author, :assigned_to, :relations_to).to_a
raise ActiveRecord::RecordNotFound if @issues.empty?
raise Unauthorized unless @issues.all?(&:visible?)
@projects = @issues.collect(&:project).compact.uniq
@@ -555,21 +578,6 @@ class ApplicationController < ActionController::Base
flash[:warning] = l(:warning_attachments_not_saved, obj.unsaved_attachments.size) if obj.unsaved_attachments.present?
end
# Sets the `flash` notice or error based the number of issues that did not save
#
# @param [Array, Issue] issues all of the saved and unsaved Issues
# @param [Array, Integer] unsaved_issue_ids the issue ids that were not saved
def set_flash_from_bulk_issue_save(issues, unsaved_issue_ids)
if unsaved_issue_ids.empty?
flash[:notice] = l(:notice_successful_update) unless issues.empty?
else
flash[:error] = l(:notice_failed_to_save_issues,
:count => unsaved_issue_ids.size,
:total => issues.size,
:ids => '#' + unsaved_issue_ids.join(', #'))
end
end
# Rescues an invalid query statement. Just in case...
def query_statement_invalid(exception)
logger.error "Query::StatementInvalid: #{exception.message}" if logger

View File

@@ -25,7 +25,7 @@ class BoardsController < ApplicationController
helper :watchers
def index
@boards = @project.boards.includes(:last_message => :author).all
@boards = @project.boards.includes(:project, :last_message => :author).all
# show the board if there is only one
if @boards.size == 1
@board = @boards.first

View File

@@ -19,17 +19,15 @@ class ContextMenusController < ApplicationController
helper :watchers
helper :issues
before_filter :find_issues, :only => :issues
def issues
@issues = Issue.visible.all(:conditions => {:id => params[:ids]}, :include => :project)
(render_404; return) unless @issues.present?
if (@issues.size == 1)
@issue = @issues.first
end
@issue_ids = @issues.map(&:id).sort
@allowed_statuses = @issues.map(&:new_statuses_allowed_to).reduce(:&)
@projects = @issues.collect(&:project).compact.uniq
@project = @projects.first if @projects.size == 1
@can = {:edit => User.current.allowed_to?(:edit_issues, @projects),
:log_time => (@project && User.current.allowed_to?(:log_time, @project)),
@@ -73,8 +71,7 @@ class ContextMenusController < ApplicationController
end
def time_entries
@time_entries = TimeEntry.all(
:conditions => {:id => params[:ids]}, :include => :project)
@time_entries = TimeEntry.where(:id => params[:ids]).preload(:project).to_a
(render_404; return) unless @time_entries.present?
@projects = @time_entries.collect(&:project).compact.uniq

View File

@@ -21,10 +21,18 @@ class CustomFieldsController < ApplicationController
before_filter :require_admin
before_filter :build_new_custom_field, :only => [:new, :create]
before_filter :find_custom_field, :only => [:edit, :update, :destroy]
accept_api_auth :index
def index
@custom_fields_by_type = CustomField.all.group_by {|f| f.class.name }
@tab = params[:tab] || 'IssueCustomField'
respond_to do |format|
format.html {
@custom_fields_by_type = CustomField.all.group_by {|f| f.class.name }
@tab = params[:tab] || 'IssueCustomField'
}
format.api {
@custom_fields = CustomField.all
}
end
end
def new

View File

@@ -70,14 +70,12 @@ class EnumerationsController < ApplicationController
@enumeration.destroy
redirect_to enumerations_path
return
elsif params[:reassign_to_id]
if reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id])
@enumeration.destroy(reassign_to)
redirect_to enumerations_path
return
end
elsif params[:reassign_to_id].present? && (reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id].to_i))
@enumeration.destroy(reassign_to)
redirect_to enumerations_path
return
end
@enumerations = @enumeration.class.all - [@enumeration]
@enumerations = @enumeration.class.system.all - [@enumeration]
end
private

View File

@@ -40,7 +40,7 @@ class IssueStatusesController < ApplicationController
def create
@issue_status = IssueStatus.new(params[:issue_status])
if request.post? && @issue_status.save
if @issue_status.save
flash[:notice] = l(:notice_successful_create)
redirect_to issue_statuses_path
else
@@ -54,7 +54,7 @@ class IssueStatusesController < ApplicationController
def update
@issue_status = IssueStatus.find(params[:id])
if request.put? && @issue_status.update_attributes(params[:issue_status])
if @issue_status.update_attributes(params[:issue_status])
flash[:notice] = l(:notice_successful_update)
redirect_to issue_statuses_path
else

View File

@@ -103,6 +103,9 @@ class IssuesController < ApplicationController
@journals = @issue.journals.includes(:user, :details).reorder("#{Journal.table_name}.id ASC").all
@journals.each_with_index {|j,i| j.indice = i+1}
@journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
Journal.preload_journals_details_custom_fields(@journals)
# TODO: use #select! when ruby1.8 support is dropped
@journals.reject! {|journal| !journal.notes? && journal.visible_details.empty?}
@journals.reverse! if User.current.wants_comments_in_reverse_order?
@changesets = @issue.changesets.visible.all
@@ -113,6 +116,8 @@ class IssuesController < ApplicationController
@edit_allowed = User.current.allowed_to?(:edit_issues, @project)
@priorities = IssuePriority.active
@time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
@relation = IssueRelation.new
respond_to do |format|
format.html {
retrieve_previous_and_next_issue_ids
@@ -176,7 +181,7 @@ class IssuesController < ApplicationController
@issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads]))
saved = false
begin
saved = @issue.save_issue_with_child_records(params, @time_entry)
saved = save_issue_with_child_records
rescue ActiveRecord::StaleObjectError
@conflict = true
if params[:last_journal_id]
@@ -228,7 +233,7 @@ class IssuesController < ApplicationController
else
@available_statuses = @issues.map(&:new_statuses_allowed_to).reduce(:&)
end
@custom_fields = target_projects.map{|p|p.all_issue_custom_fields}.reduce(:&)
@custom_fields = target_projects.map{|p|p.all_issue_custom_fields.visible}.reduce(:&)
@assignables = target_projects.map(&:assignable_users).reduce(:&)
@trackers = target_projects.map(&:trackers).reduce(:&)
@versions = target_projects.map {|p| p.shared_versions.open}.reduce(:&)
@@ -239,7 +244,9 @@ class IssuesController < ApplicationController
end
@safe_attributes = @issues.map(&:safe_attribute_names).reduce(:&)
render :layout => false if request.xhr?
@issue_params = params[:issue] || {}
@issue_params[:custom_field_values] ||= {}
end
def bulk_update
@@ -247,8 +254,8 @@ class IssuesController < ApplicationController
@copy = params[:copy].present?
attributes = parse_params_for_bulk_issue_attributes(params)
unsaved_issue_ids = []
moved_issues = []
unsaved_issues = []
saved_issues = []
if @copy && params[:copy_subtasks].present?
# Descendant issues will be copied with the parent task
@@ -256,39 +263,48 @@ class IssuesController < ApplicationController
@issues.reject! {|issue| @issues.detect {|other| issue.is_descendant_of?(other)}}
end
@issues.each do |issue|
issue.reload
@issues.each do |orig_issue|
orig_issue.reload
if @copy
issue = issue.copy({},
issue = orig_issue.copy({},
:attachments => params[:copy_attachments].present?,
:subtasks => params[:copy_subtasks].present?
)
else
issue = orig_issue
end
journal = issue.init_journal(User.current, params[:notes])
issue.safe_attributes = attributes
call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
if issue.save
moved_issues << issue
saved_issues << issue
else
# Keep unsaved issue ids to display them in flash error
unsaved_issue_ids << issue.id
unsaved_issues << orig_issue
end
end
set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids)
if params[:follow]
if @issues.size == 1 && moved_issues.size == 1
redirect_to issue_path(moved_issues.first)
elsif moved_issues.map(&:project).uniq.size == 1
redirect_to project_issues_path(moved_issues.map(&:project).first)
if unsaved_issues.empty?
flash[:notice] = l(:notice_successful_update) unless saved_issues.empty?
if params[:follow]
if @issues.size == 1 && saved_issues.size == 1
redirect_to issue_path(saved_issues.first)
elsif saved_issues.map(&:project).uniq.size == 1
redirect_to project_issues_path(saved_issues.map(&:project).first)
end
else
redirect_back_or_default _project_issues_path(@project)
end
else
redirect_back_or_default _project_issues_path(@project)
@saved_issues = @issues
@unsaved_issues = unsaved_issues
@issues = Issue.visible.find_all_by_id(@unsaved_issues.map(&:id))
bulk_edit
render :action => 'bulk_edit'
end
end
def destroy
@hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f
@hours = TimeEntry.where(:issue_id => @issues.map(&:id)).sum(:hours).to_f
if @hours > 0
case params[:todo]
when 'destroy'
@@ -436,4 +452,26 @@ class IssuesController < ApplicationController
end
attributes
end
# Saves @issue and a time_entry from the parameters
def save_issue_with_child_records
Issue.transaction do
if params[:time_entry] && (params[:time_entry][:hours].present? || params[:time_entry][:comments].present?) && User.current.allowed_to?(:log_time, @issue.project)
time_entry = @time_entry || TimeEntry.new
time_entry.project = @issue.project
time_entry.issue = @issue
time_entry.user = User.current
time_entry.spent_on = User.current.today
time_entry.attributes = params[:time_entry]
@issue.time_entries << time_entry
end
call_hook(:controller_issues_edit_before_save, { :params => params, :issue => @issue, :time_entry => time_entry, :journal => @issue.current_journal})
if @issue.save
call_hook(:controller_issues_edit_after_save, { :params => params, :issue => @issue, :time_entry => time_entry, :journal => @issue.current_journal})
else
raise ActiveRecord::Rollback
end
end
end
end

View File

@@ -35,7 +35,7 @@ class MessagesController < ApplicationController
page = params[:page]
# Find the page of the requested reply
if params[:r] && page.nil?
offset = @topic.children.count(:conditions => ["#{Message.table_name}.id < ?", params[:r].to_i])
offset = @topic.children.where("#{Message.table_name}.id < ?", params[:r].to_i).count
page = 1 + offset / REPLIES_PER_PAGE
end

View File

@@ -17,6 +17,8 @@
class MyController < ApplicationController
before_filter :require_login
# let user change user's password when user has to
skip_before_filter :check_password_change, :only => :password
helper :issues
helper :users
@@ -53,10 +55,8 @@ class MyController < ApplicationController
if request.post?
@user.safe_attributes = params[:user]
@user.pref.attributes = params[:pref]
@user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
if @user.save
@user.pref.save
@user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : [])
set_language_if_valid @user.language
flash[:notice] = l(:notice_account_updated)
redirect_to my_account_path
@@ -92,14 +92,17 @@ class MyController < ApplicationController
return
end
if request.post?
if @user.check_password?(params[:password])
if !@user.check_password?(params[:password])
flash.now[:error] = l(:notice_account_wrong_password)
elsif params[:password] == params[:new_password]
flash.now[:error] = l(:notice_new_password_must_be_different)
else
@user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
@user.must_change_passwd = false
if @user.save
flash[:notice] = l(:notice_account_password_updated)
redirect_to my_account_path
end
else
flash[:error] = l(:notice_account_wrong_password)
end
end
end

View File

@@ -82,7 +82,7 @@ class ProjectsController < ApplicationController
if validate_parent_id && @project.save
@project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
# Add current user as a project member if he is not admin
# Add current user as a project member if current user is not admin
unless User.current.admin?
r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first
m = Member.new(:user => User.current, :roles => [r])
@@ -155,7 +155,7 @@ class ProjectsController < ApplicationController
@total_issues_by_tracker = Issue.visible.where(cond).count(:group => :tracker)
if User.current.allowed_to?(:view_time_entries, @project)
@total_hours = TimeEntry.visible.sum(:hours, :include => :project, :conditions => cond).to_f
@total_hours = TimeEntry.visible.where(cond).sum(:hours).to_f
end
@key = User.current.rss_key

View File

@@ -45,7 +45,7 @@ class QueriesController < ApplicationController
@query = IssueQuery.new
@query.user = User.current
@query.project = @project
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
@query.visibility = IssueQuery::VISIBILITY_PRIVATE unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
@query.build_from_params(params)
end
@@ -53,13 +53,13 @@ class QueriesController < ApplicationController
@query = IssueQuery.new(params[:query])
@query.user = User.current
@query.project = params[:query_is_for_all] ? nil : @project
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
@query.visibility = IssueQuery::VISIBILITY_PRIVATE unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
@query.build_from_params(params)
@query.column_names = nil if params[:default_columns]
if @query.save
flash[:notice] = l(:notice_successful_create)
redirect_to _project_issues_path(@project, :query_id => @query)
redirect_to_issues(:query_id => @query)
else
render :action => 'new', :layout => !request.xhr?
end
@@ -71,13 +71,13 @@ class QueriesController < ApplicationController
def update
@query.attributes = params[:query]
@query.project = nil if params[:query_is_for_all]
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
@query.visibility = IssueQuery::VISIBILITY_PRIVATE unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
@query.build_from_params(params)
@query.column_names = nil if params[:default_columns]
if @query.save
flash[:notice] = l(:notice_successful_update)
redirect_to _project_issues_path(@project, :query_id => @query)
redirect_to_issues(:query_id => @query)
else
render :action => 'edit'
end
@@ -85,7 +85,7 @@ class QueriesController < ApplicationController
def destroy
@query.destroy
redirect_to _project_issues_path(@project, :set_filter => 1)
redirect_to_issues(:set_filter => 1)
end
private
@@ -103,4 +103,16 @@ private
rescue ActiveRecord::RecordNotFound
render_404
end
def redirect_to_issues(options)
if params[:gantt]
if @project
redirect_to project_gantt_path(@project, options)
else
redirect_to issues_gantt_path(options)
end
else
redirect_to _project_issues_path(@project, options)
end
end
end

View File

@@ -111,7 +111,7 @@ class RepositoriesController < ApplicationController
end
def show
@repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty?
@repository.fetch_changesets if @project.active? && Setting.autofetch_changesets? && @path.empty?
@entries = @repository.entries(@path, @rev)
@changeset = @repository.find_changeset_by_name(@rev)
@@ -352,15 +352,18 @@ class RepositoriesController < ApplicationController
@date_to = Date.today
@date_from = @date_to << 11
@date_from = Date.civil(@date_from.year, @date_from.month, 1)
commits_by_day = Changeset.count(
:all, :group => :commit_date,
:conditions => ["repository_id = ? AND commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to])
commits_by_day = Changeset.
where("repository_id = ? AND commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to).
group(:commit_date).
count
commits_by_month = [0] * 12
commits_by_day.each {|c| commits_by_month[(@date_to.month - c.first.to_date.month) % 12] += c.last }
changes_by_day = Change.count(
:all, :group => :commit_date, :include => :changeset,
:conditions => ["#{Changeset.table_name}.repository_id = ? AND #{Changeset.table_name}.commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to])
changes_by_day = Change.
joins(:changeset).
where("#{Changeset.table_name}.repository_id = ? AND #{Changeset.table_name}.commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to).
group(:commit_date).
count
changes_by_month = [0] * 12
changes_by_day.each {|c| changes_by_month[(@date_to.month - c.first.to_date.month) % 12] += c.last }
@@ -393,10 +396,10 @@ class RepositoriesController < ApplicationController
end
def graph_commits_per_author(repository)
commits_by_author = Changeset.count(:all, :group => :committer, :conditions => ["repository_id = ?", repository.id])
commits_by_author = Changeset.where("repository_id = ?", repository.id).group(:committer).count
commits_by_author.to_a.sort! {|x, y| x.last <=> y.last}
changes_by_author = Change.count(:all, :group => :committer, :include => :changeset, :conditions => ["#{Changeset.table_name}.repository_id = ?", repository.id])
changes_by_author = Change.joins(:changeset).where("#{Changeset.table_name}.repository_id = ?", repository.id).group(:committer).count
h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o}
fields = commits_by_author.collect {|r| r.first}
@@ -411,7 +414,7 @@ class RepositoriesController < ApplicationController
fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') }
graph = SVG::Graph::BarHorizontal.new(
:height => 400,
:height => 30 * commits_data.length,
:width => 800,
:fields => fields,
:stack => :side,

View File

@@ -33,9 +33,7 @@ class SettingsController < ApplicationController
if request.post? && params[:settings] && params[:settings].is_a?(Hash)
settings = (params[:settings] || {}).dup.symbolize_keys
settings.each do |name, value|
# remove blank values in array settings
value.delete_if {|v| v.blank? } if value.is_a?(Array)
Setting[name] = value
Setting.set_from_params name, value
end
flash[:notice] = l(:notice_successful_update)
redirect_to settings_path(:tab => params[:tab])
@@ -48,6 +46,9 @@ class SettingsController < ApplicationController
@guessed_host_and_path = request.host_with_port.dup
@guessed_host_and_path << ('/'+ Redmine::Utils.relative_url_root.gsub(%r{^\/}, '')) unless Redmine::Utils.relative_url_root.blank?
@commit_update_keywords = Setting.commit_update_keywords.dup
@commit_update_keywords = [{}] unless @commit_update_keywords.is_a?(Array) && @commit_update_keywords.any?
Redmine::Themes.rescan
end
end

View File

@@ -19,11 +19,7 @@ class SysController < ActionController::Base
before_filter :check_enabled
def projects
p = Project.active.has_module(:repository).find(
:all,
:include => :repository,
:order => "#{Project.table_name}.identifier"
)
p = Project.active.has_module(:repository).order("#{Project.table_name}.identifier").preload(:repository).all
# extra_info attribute from repository breaks activeresource client
render :xml => p.to_xml(
:only => [:id, :identifier, :name, :is_public, :status],

View File

@@ -43,22 +43,18 @@ class TimelogController < ApplicationController
def index
@query = TimeEntryQuery.build_from_params(params, :project => @project, :name => '_')
scope = time_entry_scope
sort_init(@query.sort_criteria.empty? ? [['spent_on', 'desc']] : @query.sort_criteria)
sort_update(@query.sortable_columns)
scope = time_entry_scope(:order => sort_clause).
includes(:project, :activity, :user, :issue).
preload(:issue => [:project, :tracker, :status, :assigned_to, :priority])
respond_to do |format|
format.html {
# Paginate results
@entry_count = scope.count
@entry_pages = Paginator.new @entry_count, per_page_option, params['page']
@entries = scope.all(
:include => [:project, :activity, :user, {:issue => :tracker}],
:order => sort_clause,
:limit => @entry_pages.per_page,
:offset => @entry_pages.offset
)
@entries = scope.offset(@entry_pages.offset).limit(@entry_pages.per_page).all
@total_hours = scope.sum(:hours).to_f
render :layout => !request.xhr?
@@ -66,27 +62,15 @@ class TimelogController < ApplicationController
format.api {
@entry_count = scope.count
@offset, @limit = api_offset_and_limit
@entries = scope.all(
:include => [:project, :activity, :user, {:issue => :tracker}],
:order => sort_clause,
:limit => @limit,
:offset => @offset
)
@entries = scope.offset(@offset).limit(@limit).preload(:custom_values => :custom_field).all
}
format.atom {
entries = scope.all(
:include => [:project, :activity, :user, {:issue => :tracker}],
:order => "#{TimeEntry.table_name}.created_on DESC",
:limit => Setting.feeds_limit.to_i
)
entries = scope.limit(Setting.feeds_limit.to_i).reorder("#{TimeEntry.table_name}.created_on DESC").all
render_feed(entries, :title => l(:label_spent_time))
}
format.csv {
# Export all entries
@entries = scope.all(
:include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
:order => sort_clause
)
@entries = scope.all
send_data(query_to_csv(@entries, @query, params), :type => 'text/csv; header=present', :filename => 'timelog.csv')
}
end
@@ -198,6 +182,7 @@ class TimelogController < ApplicationController
time_entry.safe_attributes = attributes
call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry })
unless time_entry.save
logger.info "time entry could not be updated: #{time_entry.errors.full_messages}" if logger && logger.info
# Keep unsaved time_entry ids to display them in flash error
unsaved_time_entry_ids << time_entry.id
end
@@ -295,12 +280,10 @@ private
end
# Returns the TimeEntry scope for index and report actions
def time_entry_scope
scope = TimeEntry.visible.where(@query.statement)
def time_entry_scope(options={})
scope = @query.results_scope(options)
if @issue
scope = scope.on_issue(@issue)
elsif @project
scope = scope.on_project(@project, Setting.display_subprojects_issues?)
end
scope
end

View File

@@ -60,7 +60,7 @@ class UsersController < ApplicationController
def show
# show projects based on current user visibility
@memberships = @user.memberships.all(:conditions => Project.visible_condition(User.current))
@memberships = @user.memberships.where(Project.visible_condition(User.current)).all
events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10)
@events_by_day = events.group_by(&:event_date)
@@ -80,6 +80,7 @@ class UsersController < ApplicationController
def new
@user = User.new(:language => Setting.default_language, :mail_notification => Setting.default_notification_option)
@user.safe_attributes = params[:user]
@auth_sources = AuthSource.all
end
@@ -92,17 +93,16 @@ class UsersController < ApplicationController
if @user.save
@user.pref.attributes = params[:pref]
@user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
@user.pref.save
@user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : [])
Mailer.account_information(@user, params[:user][:password]).deliver if params[:send_information]
Mailer.account_information(@user, @user.password).deliver if params[:send_information]
respond_to do |format|
format.html {
flash[:notice] = l(:notice_user_successful_create, :id => view_context.link_to(@user.login, user_path(@user)))
if params[:continue]
redirect_to new_user_path
attrs = params[:user].slice(:generate_password)
redirect_to new_user_path(:user => attrs)
else
redirect_to edit_user_path(@user)
end
@@ -137,16 +137,14 @@ class UsersController < ApplicationController
was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE])
# TODO: Similar to My#account
@user.pref.attributes = params[:pref]
@user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
if @user.save
@user.pref.save
@user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : [])
if was_activated
Mailer.account_activated(@user).deliver
elsif @user.active? && params[:send_information] && !params[:user][:password].blank? && @user.auth_source_id.nil?
Mailer.account_information(@user, params[:user][:password]).deliver
elsif @user.active? && params[:send_information] && @user.password.present? && @user.auth_source_id.nil?
Mailer.account_information(@user, @user.password).deliver
end
respond_to do |format|

View File

@@ -46,11 +46,11 @@ class VersionsController < ApplicationController
@issues_by_version = {}
if @selected_tracker_ids.any? && @versions.any?
issues = Issue.visible.all(
:include => [:project, :status, :tracker, :priority, :fixed_version],
:conditions => {:tracker_id => @selected_tracker_ids, :project_id => project_ids, :fixed_version_id => @versions.map(&:id)},
:order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id"
)
issues = Issue.visible.
includes(:project, :tracker).
preload(:status, :priority, :fixed_version).
where(:tracker_id => @selected_tracker_ids, :project_id => project_ids, :fixed_version_id => @versions.map(&:id)).
order("#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id")
@issues_by_version = issues.group_by(&:fixed_version)
end
@versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?}

View File

@@ -15,8 +15,6 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'diff'
# The WikiController follows the Rails REST controller pattern but with
# a few differences
#
@@ -64,7 +62,12 @@ class WikiController < ApplicationController
# display a page (in editing mode if it doesn't exist)
def show
if @page.new_record?
if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project)
deny_access
return
end
@content = @page.content_for_version(params[:version])
if @content.nil?
if User.current.allowed_to?(:edit_wiki_pages, @project) && editable? && !api_request?
edit
render :action => 'edit'
@@ -73,11 +76,6 @@ class WikiController < ApplicationController
end
return
end
if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project)
deny_access
return
end
@content = @page.content_for_version(params[:version])
if User.current.allowed_to?(:export_wiki_pages, @project)
if params[:format] == 'pdf'
send_data(wiki_page_to_pdf(@page, @project), :type => 'application/pdf', :filename => "#{@page.title}.pdf")
@@ -106,19 +104,19 @@ class WikiController < ApplicationController
def edit
return render_403 unless editable?
if @page.new_record?
@page.content = WikiContent.new(:page => @page)
if params[:parent].present?
@page.parent = @page.wiki.find_page(params[:parent].to_s)
end
end
@content = @page.content_for_version(params[:version])
@content ||= WikiContent.new(:page => @page)
@content.text = initial_page_content(@page) if @content.text.blank?
# don't keep previous comment
@content.comments = nil
# To prevent StaleObjectError exception when reverting to a previous version
@content.version = @page.content.version
@content.version = @page.content.version if @page.content
@text = @content.text
if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
@@ -132,10 +130,9 @@ class WikiController < ApplicationController
def update
return render_403 unless editable?
was_new_page = @page.new_record?
@page.content = WikiContent.new(:page => @page) if @page.new_record?
@page.safe_attributes = params[:wiki_page]
@content = @page.content
@content = @page.content || WikiContent.new(:page => @page)
content_params = params[:content]
if content_params.nil? && params[:wiki_page].is_a?(Hash)
content_params = params[:wiki_page].slice(:text, :comments, :version)
@@ -147,20 +144,23 @@ class WikiController < ApplicationController
if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
@section = params[:section].to_i
@section_hash = params[:section_hash]
@content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(params[:section].to_i, @text, @section_hash)
@content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(@section, @text, @section_hash)
else
@content.version = content_params[:version] if content_params[:version]
@content.text = @text
end
@content.author = User.current
if @page.save_with_content
if @page.save_with_content(@content)
attachments = Attachment.attach_files(@page, params[:attachments])
render_attachment_warning_if_needed(@page)
call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})
respond_to do |format|
format.html { redirect_to project_wiki_page_path(@project, @page.title) }
format.html {
anchor = @section ? "section-#{@section}" : nil
redirect_to project_wiki_page_path(@project, @page.title, :anchor => anchor)
}
format.api {
if was_new_page
render :action => 'show', :status => :created, :location => project_wiki_page_path(@project, @page.title)

View File

@@ -330,7 +330,7 @@ module ApplicationHelper
end
groups = ''
collection.sort.each do |element|
selected_attribute = ' selected="selected"' if option_value_selected?(element, selected)
selected_attribute = ' selected="selected"' if option_value_selected?(element, selected) || element.id.to_s == selected
(element.is_a?(Group) ? groups : s) << %(<option value="#{element.id}"#{selected_attribute}>#{h element.name}</option>)
end
unless groups.empty?
@@ -348,6 +348,10 @@ module ApplicationHelper
options
end
def option_tag(name, text, value, selected=nil, options={})
content_tag 'option', value, options.merge(:value => value, :selected => (value == selected))
end
# Truncates and returns the string as a single line
def truncate_single_line(string, *args)
truncate(string.to_s, *args).gsub(%r{[\r\n]+}m, ' ')
@@ -380,7 +384,7 @@ module ApplicationHelper
if @project
link_to(text, {:controller => 'activities', :action => 'index', :id => @project, :from => User.current.time_to_date(time)}, :title => format_time(time))
else
content_tag('acronym', text, :title => format_time(time))
content_tag('abbr', text, :title => format_time(time))
end
end
@@ -445,12 +449,31 @@ module ApplicationHelper
end
end
# Returns a h2 tag and sets the html title with the given arguments
def title(*args)
strings = args.map do |arg|
if arg.is_a?(Array) && arg.size >= 2
link_to(*arg)
else
h(arg.to_s)
end
end
html_title args.reverse.map {|s| (s.is_a?(Array) ? s.first : s).to_s}
content_tag('h2', strings.join(' &#187; ').html_safe)
end
# Sets the html title
# Returns the html title when called without arguments
# Current project name and app_title and automatically appended
# Exemples:
# html_title 'Foo', 'Bar'
# html_title # => 'Foo - Bar - My Project - Redmine'
def html_title(*args)
if args.empty?
title = @html_title || []
title << @project.name if @project
title << Setting.app_title unless Setting.app_title == title.last
title.select {|t| !t.blank? }.join(' - ')
title.reject(&:blank?).join(' - ')
else
@html_title ||= []
@html_title += args
@@ -465,6 +488,7 @@ module ApplicationHelper
css << 'theme-' + theme.name
end
css << 'project-' + @project.identifier if @project && @project.identifier.present?
css << 'controller-' + controller_name
css << 'action-' + action_name
css.join(' ')
@@ -615,7 +639,7 @@ module ApplicationHelper
else
wiki_page_id = page.present? ? Wiki.titleize(page) : nil
parent = wiki_page.nil? && obj.is_a?(WikiContent) && obj.page && project == link_project ? obj.page.title : nil
url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project,
url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project,
:id => wiki_page_id, :version => nil, :anchor => anchor, :parent => parent)
end
end
@@ -656,6 +680,9 @@ module ApplicationHelper
# export:some/file -> Force the download of the file
# Forum messages:
# message#1218 -> Link to message with id 1218
# Projects:
# project:someproject -> Link to project named "someproject"
# project#3 -> Link to project with id 3
#
# Links can refer other objects from other projects, using project identifier:
# identifier:r52
@@ -692,7 +719,7 @@ module ApplicationHelper
when nil
if oid.to_s == identifier && issue = Issue.visible.find_by_id(oid, :include => :status)
anchor = comment_id ? "note-#{comment_id}" : nil
link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid, :anchor => anchor},
link = link_to(h("##{oid}#{comment_suffix}"), {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid, :anchor => anchor},
:class => issue.css_classes,
:title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})")
end
@@ -804,7 +831,8 @@ module ApplicationHelper
content_tag('div',
link_to(image_tag('edit.png'), options[:edit_section_links].merge(:section => @current_section)),
:class => 'contextual',
:title => l(:button_edit_section)) + heading.html_safe
:title => l(:button_edit_section),
:id => "section-#{@current_section}") + heading.html_safe
else
heading
end
@@ -975,7 +1003,7 @@ module ApplicationHelper
html << "</ul></div>\n"
end
html.html_safe
end
end
def delete_link(url, options={})
options = {
@@ -989,8 +1017,8 @@ module ApplicationHelper
def preview_link(url, form, target='preview', options={})
content_tag 'a', l(:label_preview), {
:href => "#",
:onclick => %|submitPreview("#{escape_javascript url_for(url)}", "#{escape_javascript form}", "#{escape_javascript target}"); return false;|,
:href => "#",
:onclick => %|submitPreview("#{escape_javascript url_for(url)}", "#{escape_javascript form}", "#{escape_javascript target}"); return false;|,
:accesskey => accesskey(:preview)
}.merge(options)
end
@@ -1035,7 +1063,7 @@ module ApplicationHelper
(pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : ''.html_safe) +
(pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) +
(pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe)
), :class => 'progress', :style => "width: #{width};").html_safe +
), :class => 'progress progress-#{pcts[0]}', :style => "width: #{width};").html_safe +
content_tag('p', legend, :class => 'percent').html_safe
end
@@ -1068,6 +1096,7 @@ module ApplicationHelper
def include_calendar_headers_tags
unless @calendar_headers_tags_included
tags = javascript_include_tag("datepicker")
@calendar_headers_tags_included = true
content_for :header_tags do
start_of_week = Setting.start_of_week
@@ -1075,15 +1104,16 @@ module ApplicationHelper
# Redmine uses 1..7 (monday..sunday) in settings and locales
# JQuery uses 0..6 (sunday..saturday), 7 needs to be changed to 0
start_of_week = start_of_week.to_i % 7
tags = javascript_tag(
tags << javascript_tag(
"var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " +
"showOn: 'button', buttonImageOnly: true, buttonImage: '" +
"showOn: 'button', buttonImageOnly: true, buttonImage: '" +
path_to_image('/images/calendar.png') +
"', showButtonPanel: true, showWeek: true, showOtherMonths: true, selectOtherMonths: true};")
"', showButtonPanel: true, showWeek: true, showOtherMonths: true, " +
"selectOtherMonths: true, changeMonth: true, changeYear: true, " +
"beforeShow: beforeShowDatePicker};")
jquery_locale = l('jquery.locale', :default => current_language.to_s)
unless jquery_locale == 'en'
tags << javascript_include_tag("i18n/jquery.ui.datepicker-#{jquery_locale}.js")
tags << javascript_include_tag("i18n/jquery.ui.datepicker-#{jquery_locale}.js")
end
tags
end

View File

@@ -19,8 +19,29 @@
module CustomFieldsHelper
CUSTOM_FIELDS_TABS = [
{:name => 'IssueCustomField', :partial => 'custom_fields/index',
:label => :label_issue_plural},
{:name => 'TimeEntryCustomField', :partial => 'custom_fields/index',
:label => :label_spent_time},
{:name => 'ProjectCustomField', :partial => 'custom_fields/index',
:label => :label_project_plural},
{:name => 'VersionCustomField', :partial => 'custom_fields/index',
:label => :label_version_plural},
{:name => 'UserCustomField', :partial => 'custom_fields/index',
:label => :label_user_plural},
{:name => 'GroupCustomField', :partial => 'custom_fields/index',
:label => :label_group_plural},
{:name => 'TimeEntryActivityCustomField', :partial => 'custom_fields/index',
:label => TimeEntryActivity::OptionName},
{:name => 'IssuePriorityCustomField', :partial => 'custom_fields/index',
:label => IssuePriority::OptionName},
{:name => 'DocumentCategoryCustomField', :partial => 'custom_fields/index',
:label => DocumentCategory::OptionName}
]
def custom_fields_tabs
CustomField::CUSTOM_FIELDS_TABS
CUSTOM_FIELDS_TABS
end
# Return custom field html tag corresponding to its format
@@ -77,32 +98,44 @@ module CustomFieldsHelper
custom_field_label_tag(name, custom_value, options) + custom_field_tag(name, custom_value)
end
def custom_field_tag_for_bulk_edit(name, custom_field, projects=nil)
def custom_field_tag_for_bulk_edit(name, custom_field, projects=nil, value='')
field_name = "#{name}[custom_field_values][#{custom_field.id}]"
field_name << "[]" if custom_field.multiple?
field_id = "#{name}_custom_field_values_#{custom_field.id}"
tag_options = {:id => field_id, :class => "#{custom_field.field_format}_cf"}
unset_tag = ''
unless custom_field.is_required?
unset_tag = content_tag('label',
check_box_tag(field_name, '__none__', (value == '__none__'), :id => nil, :data => {:disables => "##{field_id}"}) + l(:button_clear),
:class => 'inline'
)
end
field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format)
case field_format.try(:edit_as)
when "date"
text_field_tag(field_name, '', tag_options.merge(:size => 10)) +
calendar_for(field_id)
text_field_tag(field_name, value, tag_options.merge(:size => 10)) +
calendar_for(field_id) +
unset_tag
when "text"
text_area_tag(field_name, '', tag_options.merge(:rows => 3))
text_area_tag(field_name, value, tag_options.merge(:rows => 3)) +
'<br />'.html_safe +
unset_tag
when "bool"
select_tag(field_name, options_for_select([[l(:label_no_change_option), ''],
[l(:general_text_yes), '1'],
[l(:general_text_no), '0']]), tag_options)
[l(:general_text_no), '0']], value), tag_options)
when "list"
options = []
options << [l(:label_no_change_option), ''] unless custom_field.multiple?
options << [l(:label_none), '__none__'] unless custom_field.is_required?
options += custom_field.possible_values_options(projects)
select_tag(field_name, options_for_select(options), tag_options.merge(:multiple => custom_field.multiple?))
select_tag(field_name, options_for_select(options, value), tag_options.merge(:multiple => custom_field.multiple?))
else
text_field_tag(field_name, '', tag_options)
text_field_tag(field_name, value, tag_options) +
unset_tag
end
end

View File

@@ -94,6 +94,20 @@ module IssuesHelper
s.html_safe
end
# Returns an array of error messages for bulk edited issues
def bulk_edit_error_messages(issues)
messages = {}
issues.each do |issue|
issue.errors.full_messages.each do |message|
messages[message] ||= []
messages[message] << issue
end
end
messages.map { |message, issues|
"#{message}: " + issues.map {|i| "##{i.id}"}.join(', ')
}
end
# Returns a link for adding a new subtask to the given issue
def link_to_new_subtask(issue)
attrs = {
@@ -146,12 +160,13 @@ module IssuesHelper
end
def render_custom_fields_rows(issue)
return if issue.custom_field_values.empty?
values = issue.visible_custom_field_values
return if values.empty?
ordered_values = []
half = (issue.custom_field_values.size / 2.0).ceil
half = (values.size / 2.0).ceil
half.times do |i|
ordered_values << issue.custom_field_values[i]
ordered_values << issue.custom_field_values[i + half]
ordered_values << values[i]
ordered_values << values[i + half]
end
s = "<tr>\n"
n = 0
@@ -184,36 +199,60 @@ module IssuesHelper
def sidebar_queries
unless @sidebar_queries
@sidebar_queries = IssueQuery.visible.all(
:order => "#{Query.table_name}.name ASC",
@sidebar_queries = IssueQuery.visible.
order("#{Query.table_name}.name ASC").
# Project specific queries and global queries
:conditions => (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id])
)
where(@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id]).
all
end
@sidebar_queries
end
def query_links(title, queries)
return '' if queries.empty?
# links to #index on issues/show
url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : params
content_tag('h3', h(title)) +
queries.collect {|query|
css = 'query'
css << ' selected' if query == @query
link_to(h(query.name), url_params.merge(:query_id => query), :class => css)
}.join('<br />').html_safe
content_tag('h3', title) + "\n" +
content_tag('ul',
queries.collect {|query|
css = 'query'
css << ' selected' if query == @query
content_tag('li', link_to(query.name, url_params.merge(:query_id => query), :class => css))
}.join("\n").html_safe,
:class => 'queries'
) + "\n"
end
def render_sidebar_queries
out = ''.html_safe
queries = sidebar_queries.select {|q| !q.is_public?}
out << query_links(l(:label_my_queries), queries) if queries.any?
queries = sidebar_queries.select {|q| q.is_public?}
out << query_links(l(:label_query_plural), queries) if queries.any?
out << query_links(l(:label_my_queries), sidebar_queries.select(&:is_private?))
out << query_links(l(:label_query_plural), sidebar_queries.reject(&:is_private?))
out
end
def email_issue_attributes(issue, user)
items = []
%w(author status priority assigned_to category fixed_version).each do |attribute|
unless issue.disabled_core_fields.include?(attribute+"_id")
items << "#{l("field_#{attribute}")}: #{issue.send attribute}"
end
end
issue.visible_custom_field_values(user).each do |value|
items << "#{value.custom_field.name}: #{show_value(value)}"
end
items
end
def render_email_issue_attributes(issue, user, html=false)
items = email_issue_attributes(issue, user)
if html
content_tag('ul', items.map{|s| content_tag('li', s)}.join("\n").html_safe)
else
items.map{|s| "* #{s}"}.join("\n")
end
end
# Returns the textual representation of a journal details
# as an array of strings
def details_to_strings(details, no_html=false, options={})
@@ -222,23 +261,23 @@ module IssuesHelper
values_by_field = {}
details.each do |detail|
if detail.property == 'cf'
field_id = detail.prop_key
field = CustomField.find_by_id(field_id)
field = detail.custom_field
if field && field.multiple?
values_by_field[field_id] ||= {:added => [], :deleted => []}
values_by_field[field] ||= {:added => [], :deleted => []}
if detail.old_value
values_by_field[field_id][:deleted] << detail.old_value
values_by_field[field][:deleted] << detail.old_value
end
if detail.value
values_by_field[field_id][:added] << detail.value
values_by_field[field][:added] << detail.value
end
next
end
end
strings << show_detail(detail, no_html, options)
end
values_by_field.each do |field_id, changes|
detail = JournalDetail.new(:property => 'cf', :prop_key => field_id)
values_by_field.each do |field, changes|
detail = JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s)
detail.instance_variable_set "@custom_field", field
if changes[:added].any?
detail.value = changes[:added]
strings << show_detail(detail, no_html, options)
@@ -281,7 +320,7 @@ module IssuesHelper
old_value = l(detail.old_value == "0" ? :general_text_No : :general_text_Yes) unless detail.old_value.blank?
end
when 'cf'
custom_field = CustomField.find_by_id(detail.prop_key)
custom_field = detail.custom_field
if custom_field
multiple = custom_field.multiple?
label = custom_field.name
@@ -290,6 +329,17 @@ module IssuesHelper
end
when 'attachment'
label = l(:label_attachment)
when 'relation'
if detail.value && !detail.old_value
rel_issue = Issue.visible.find_by_id(detail.value)
value = rel_issue.nil? ? "#{l(:label_issue)} ##{detail.value}" :
(no_html ? rel_issue : link_to_issue(rel_issue))
elsif detail.old_value && !detail.value
rel_issue = Issue.visible.find_by_id(detail.old_value)
old_value = rel_issue.nil? ? "#{l(:label_issue)} ##{detail.old_value}" :
(no_html ? rel_issue : link_to_issue(rel_issue))
end
label = l(detail.prop_key.to_sym)
end
call_hook(:helper_issues_show_detail_after_setting,
{:detail => detail, :label => label, :value => value, :old_value => old_value })
@@ -301,7 +351,9 @@ module IssuesHelper
unless no_html
label = content_tag('strong', label)
old_value = content_tag("i", h(old_value)) if detail.old_value
old_value = content_tag("del", old_value) if detail.old_value and detail.value.blank?
if detail.old_value && detail.value.blank? && detail.property != 'relation'
old_value = content_tag("del", old_value)
end
if detail.property == 'attachment' && !value.blank? && atta = Attachment.find_by_id(detail.prop_key)
# Link to the attachment if it has not been removed
value = link_to_attachment(atta, :download => true, :only_path => options[:only_path])
@@ -337,7 +389,7 @@ module IssuesHelper
else
l(:text_journal_set_to, :label => label, :value => value).html_safe
end
when 'attachment'
when 'attachment', 'relation'
l(:text_journal_added, :label => label, :value => value).html_safe
end
else

View File

@@ -46,7 +46,7 @@ module ProjectsHelper
end
options = ''
options << "<option value=''></option>" if project.allowed_parents.include?(nil)
options << "<option value=''>&nbsp;</option>" if project.allowed_parents.include?(nil)
options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected)
content_tag('select', options.html_safe, :name => 'project[parent_id]', :id => 'project_parent_id')
end
@@ -69,10 +69,11 @@ module ProjectsHelper
grouped[version.project.name] << [version.name, version.id]
end
selected = selected.is_a?(Version) ? selected.id : selected
if grouped.keys.size > 1
grouped_options_for_select(grouped, selected && selected.id)
grouped_options_for_select(grouped, selected)
else
options_for_select((grouped.values.first || []), selected && selected.id)
options_for_select((grouped.values.first || []), selected)
end
end

View File

@@ -185,7 +185,7 @@ module QueriesHelper
if !params[:query_id].blank?
cond = "project_id IS NULL"
cond << " OR project_id = #{@project.id}" if @project
@query = IssueQuery.find(params[:query_id], :conditions => cond)
@query = IssueQuery.where(cond).find(params[:query_id])
raise ::Unauthorized unless @query.visible?
@query.project = @project
session[:query] = {:id => @query.id, :project_id => @query.project_id}
@@ -198,6 +198,7 @@ module QueriesHelper
session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
else
# retrieve from session
@query = nil
@query = IssueQuery.find_by_id(session[:query][:id]) if session[:query][:id]
@query ||= IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
@query.project = @project

View File

@@ -24,7 +24,7 @@ module ReportsHelper
data.each { |row|
match = 1
criteria.each { |k, v|
match = 0 unless (row[k].to_s == v.to_s) || (k == 'closed' && row[k] == (v == 0 ? "f" : "t"))
match = 0 unless (row[k].to_s == v.to_s) || (k == 'closed' && (v == 0 ? ['f', false] : ['t', true]).include?(row[k]))
} unless criteria.nil?
a = a + row["total"].to_i if match == 1
} unless data.nil?

View File

@@ -35,12 +35,9 @@ module VersionsHelper
h = Hash.new {|k,v| k[v] = [0, 0]}
begin
# Total issue count
Issue.count(:group => criteria,
:conditions => ["#{Issue.table_name}.fixed_version_id = ?", version.id]).each {|c,s| h[c][0] = s}
Issue.where(:fixed_version_id => version.id).group(criteria).count.each {|c,s| h[c][0] = s}
# Open issues count
Issue.count(:group => criteria,
:include => :status,
:conditions => ["#{Issue.table_name}.fixed_version_id = ? AND #{IssueStatus.table_name}.is_closed = ?", version.id, false]).each {|c,s| h[c][1] = s}
Issue.open.where(:fixed_version_id => version.id).group(criteria).count.each {|c,s| h[c][1] = s}
rescue ActiveRecord::RecordNotFound
# When grouping by an association, Rails throws this exception if there's no result (bug)
end

View File

@@ -28,7 +28,7 @@ module WatchersHelper
return '' unless user && user.logged?
objects = Array.wrap(objects)
watched = objects.any? {|object| object.watched_by?(user)}
watched = Watcher.any_watched?(objects, user)
css = [watcher_css(objects), watched ? 'icon icon-fav' : 'icon icon-fav-off'].join(' ')
text = watched ? l(:button_unwatch) : l(:button_watch)
url = watch_path(

View File

@@ -22,11 +22,20 @@ module WorkflowsHelper
field.is_a?(CustomField) ? field.is_required? : %w(project_id tracker_id subject priority_id is_private).include?(field)
end
def field_permission_tag(permissions, status, field)
def field_permission_tag(permissions, status, field, role)
name = field.is_a?(CustomField) ? field.id.to_s : field
options = [["", ""], [l(:label_readonly), "readonly"]]
options << [l(:label_required), "required"] unless field_required?(field)
html_options = {}
selected = permissions[status.id][name]
select_tag("permissions[#{name}][#{status.id}]", options_for_select(options, permissions[status.id][name]))
hidden = field.is_a?(CustomField) && !field.visible? && !role.custom_fields.to_a.include?(field)
if hidden
options[0][0] = l(:label_hidden)
selected = ''
html_options[:disabled] = true
end
select_tag("permissions[#{name}][#{status.id}]", options_for_select(options, selected), html_options)
end
end

View File

@@ -102,7 +102,7 @@ class Attachment < ActiveRecord::Base
if @temp_file && (@temp_file.size > 0)
self.disk_directory = target_directory
self.disk_filename = Attachment.disk_filename(filename, disk_directory)
logger.info("Saving attachment '#{self.diskfile}' (#{@temp_file.size} bytes)")
logger.info("Saving attachment '#{self.diskfile}' (#{@temp_file.size} bytes)") if logger
path = File.dirname(diskfile)
unless File.directory?(path)
FileUtils.mkdir_p(path)
@@ -294,10 +294,10 @@ class Attachment < ActiveRecord::Base
def sanitize_filename(value)
# get only the filename, not the whole path
just_filename = value.gsub(/^.*(\\|\/)/, '')
just_filename = value.gsub(/\A.*(\\|\/)/m, '')
# Finally, replace invalid characters with underscore
@filename = just_filename.gsub(/[\/\?\%\*\:\|\"\'<>]+/, '_')
@filename = just_filename.gsub(/[\/\?\%\*\:\|\"\'<>\n\r]+/, '_')
end
# Returns the subdirectory in which the attachment will be saved

View File

@@ -118,22 +118,25 @@ class Changeset < ActiveRecord::Base
ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip)
ref_keywords_any = ref_keywords.delete('*')
# keywords used to fix issues
fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip)
fix_keywords = Setting.commit_update_keywords_array.map {|r| r['keywords']}.flatten.compact
kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|")
referenced_issues = []
comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match|
action, refs = match[2], match[3]
action, refs = match[2].to_s.downcase, match[3]
next unless action.present? || ref_keywords_any
refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m|
issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2]
if issue
referenced_issues << issue
fix_issue(issue) if fix_keywords.include?(action.to_s.downcase)
log_time(issue, hours) if hours && Setting.commit_logtime_enabled?
# Don't update issues or log time when importing old commits
unless repository.created_on && committed_on && committed_on < repository.created_on
fix_issue(issue, action) if fix_keywords.include?(action)
log_time(issue, hours) if hours && Setting.commit_logtime_enabled?
end
end
end
end
@@ -210,25 +213,26 @@ class Changeset < ActiveRecord::Base
private
def fix_issue(issue)
status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i)
if status.nil?
logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger
return issue
end
# Updates the +issue+ according to +action+
def fix_issue(issue, action)
# the issue may have been updated by the closure of another one (eg. duplicate)
issue.reload
# don't change the status is the issue is closed
return if issue.status && issue.status.is_closed?
journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag(issue.project)))
issue.status = status
unless Setting.commit_fix_done_ratio.blank?
issue.done_ratio = Setting.commit_fix_done_ratio.to_i
journal = issue.init_journal(user || User.anonymous,
ll(Setting.default_language,
:text_status_changed_by_changeset,
text_tag(issue.project)))
rule = Setting.commit_update_keywords_array.detect do |rule|
rule['keywords'].include?(action) &&
(rule['if_tracker_id'].blank? || rule['if_tracker_id'] == issue.tracker_id.to_s)
end
if rule
issue.assign_attributes rule.slice(*Issue.attribute_names)
end
Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update,
{ :changeset => self, :issue => issue })
{ :changeset => self, :issue => issue, :action => action })
unless issue.save
logger.warn("Issue ##{issue.id} could not be saved by changeset #{id}: #{issue.errors.full_messages}") if logger
end

View File

@@ -22,5 +22,16 @@ class Comment < ActiveRecord::Base
validates_presence_of :commented, :author, :comments
after_create :send_notification
safe_attributes 'comments'
private
def send_notification
mailer_method = "#{commented.class.name.underscore}_comment_added"
if Setting.notified_events.include?(mailer_method)
Mailer.send(mailer_method, self).deliver
end
end
end

View File

@@ -1,24 +0,0 @@
# Redmine - project management software
# Copyright (C) 2006-2013 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.
class CommentObserver < ActiveRecord::Observer
def after_create(comment)
if comment.commented.is_a?(News) && Setting.notified_events.include?('news_comment_added')
Mailer.news_comment_added(comment).deliver
end
end
end

View File

@@ -19,6 +19,7 @@ class CustomField < ActiveRecord::Base
include Redmine::SubclassFactory
has_many :custom_values, :dependent => :delete_all
has_and_belongs_to_many :roles, :join_table => "#{table_name_prefix}custom_fields_roles#{table_name_suffix}", :foreign_key => "custom_field_id"
acts_as_list :scope => 'type = \'#{self.class}\''
serialize :possible_values
@@ -26,35 +27,35 @@ class CustomField < ActiveRecord::Base
validates_uniqueness_of :name, :scope => :type
validates_length_of :name, :maximum => 30
validates_inclusion_of :field_format, :in => Redmine::CustomFieldFormat.available_formats
validate :validate_custom_field
before_validation :set_searchable
after_save :handle_multiplicity_change
after_save do |field|
if field.visible_changed? && field.visible
field.roles.clear
end
end
scope :sorted, lambda { order("#{table_name}.position ASC") }
scope :visible, lambda {|*args|
user = args.shift || User.current
if user.admin?
# nop
elsif user.memberships.any?
where("#{table_name}.visible = ? OR #{table_name}.id IN (SELECT DISTINCT cfr.custom_field_id FROM #{Member.table_name} m" +
" INNER JOIN #{MemberRole.table_name} mr ON mr.member_id = m.id" +
" INNER JOIN #{table_name_prefix}custom_fields_roles#{table_name_suffix} cfr ON cfr.role_id = mr.role_id" +
" WHERE m.user_id = ?)",
true, user.id)
else
where(:visible => true)
end
}
CUSTOM_FIELDS_TABS = [
{:name => 'IssueCustomField', :partial => 'custom_fields/index',
:label => :label_issue_plural},
{:name => 'TimeEntryCustomField', :partial => 'custom_fields/index',
:label => :label_spent_time},
{:name => 'ProjectCustomField', :partial => 'custom_fields/index',
:label => :label_project_plural},
{:name => 'VersionCustomField', :partial => 'custom_fields/index',
:label => :label_version_plural},
{:name => 'UserCustomField', :partial => 'custom_fields/index',
:label => :label_user_plural},
{:name => 'GroupCustomField', :partial => 'custom_fields/index',
:label => :label_group_plural},
{:name => 'TimeEntryActivityCustomField', :partial => 'custom_fields/index',
:label => TimeEntryActivity::OptionName},
{:name => 'IssuePriorityCustomField', :partial => 'custom_fields/index',
:label => IssuePriority::OptionName},
{:name => 'DocumentCategoryCustomField', :partial => 'custom_fields/index',
:label => DocumentCategory::OptionName}
]
CUSTOM_FIELDS_NAMES = CUSTOM_FIELDS_TABS.collect{|v| v[:name]}
def visible_by?(project, user=User.current)
visible? || user.admin?
end
def field_format=(arg)
# cannot change format of a saved custom field
@@ -122,8 +123,10 @@ class CustomField < ActiveRecord::Base
values.each do |value|
value.force_encoding('UTF-8') if value.respond_to?(:force_encoding)
end
values
else
[]
end
values || []
end
end
@@ -215,6 +218,7 @@ class CustomField < ActiveRecord::Base
" ON #{join_alias}.customized_type = '#{self.class.customized_class.base_class.name}'" +
" AND #{join_alias}.customized_id = #{self.class.customized_class.table_name}.id" +
" AND #{join_alias}.custom_field_id = #{id}" +
" AND (#{visibility_by_project_condition})" +
" AND #{join_alias}.value <> ''" +
" AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" +
" WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" +
@@ -227,6 +231,7 @@ class CustomField < ActiveRecord::Base
" ON #{join_alias}.customized_type = '#{self.class.customized_class.base_class.name}'" +
" AND #{join_alias}.customized_id = #{self.class.customized_class.table_name}.id" +
" AND #{join_alias}.custom_field_id = #{id}" +
" AND (#{visibility_by_project_condition})" +
" AND #{join_alias}.value <> ''" +
" AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" +
" WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" +
@@ -237,6 +242,7 @@ class CustomField < ActiveRecord::Base
" ON #{join_alias}.customized_type = '#{self.class.customized_class.base_class.name}'" +
" AND #{join_alias}.customized_id = #{self.class.customized_class.table_name}.id" +
" AND #{join_alias}.custom_field_id = #{id}" +
" AND (#{visibility_by_project_condition})" +
" AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" +
" WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" +
" AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" +
@@ -254,6 +260,33 @@ class CustomField < ActiveRecord::Base
join_alias + "_" + field_format
end
def visibility_by_project_condition(project_key=nil, user=User.current)
if visible? || user.admin?
"1=1"
elsif user.anonymous?
"1=0"
else
project_key ||= "#{self.class.customized_class.table_name}.project_id"
"#{project_key} IN (SELECT DISTINCT m.project_id FROM #{Member.table_name} m" +
" INNER JOIN #{MemberRole.table_name} mr ON mr.member_id = m.id" +
" INNER JOIN #{table_name_prefix}custom_fields_roles#{table_name_suffix} cfr ON cfr.role_id = mr.role_id" +
" WHERE m.user_id = #{user.id} AND cfr.custom_field_id = #{id})"
end
end
def self.visibility_condition
if user.admin?
"1=1"
elsif user.anonymous?
"#{table_name}.visible"
else
"#{project_key} IN (SELECT DISTINCT m.project_id FROM #{Member.table_name} m" +
" INNER JOIN #{MemberRole.table_name} mr ON mr.member_id = m.id" +
" INNER JOIN #{table_name_prefix}custom_fields_roles#{table_name_suffix} cfr ON cfr.role_id = mr.role_id" +
" WHERE m.user_id = #{user.id} AND cfr.custom_field_id = #{id})"
end
end
def <=>(field)
position <=> field.position
end
@@ -270,7 +303,7 @@ class CustomField < ActiveRecord::Base
def self.customized_class
self.name =~ /^(.+)CustomField$/
begin; $1.constantize; rescue nil; end
$1.constantize rescue nil
end
# to move in project_custom_field

View File

@@ -30,6 +30,8 @@ class Document < ActiveRecord::Base
validates_presence_of :project, :title, :category
validates_length_of :title, :maximum => 60
after_create :send_notification
scope :visible, lambda {|*args|
includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_documents, *args))
}
@@ -54,4 +56,12 @@ class Document < ActiveRecord::Base
end
@updated_on
end
private
def send_notification
if Setting.notified_events.include?('document_added')
Mailer.document_added(self).deliver
end
end
end

View File

@@ -38,6 +38,7 @@ class Enumeration < ActiveRecord::Base
scope :shared, lambda { where(:project_id => nil) }
scope :sorted, lambda { order("#{table_name}.position ASC") }
scope :active, lambda { where(:active => true) }
scope :system, lambda { where(:project_id => nil) }
scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
def self.default

View File

@@ -18,6 +18,7 @@
class Issue < ActiveRecord::Base
include Redmine::SafeAttributes
include Redmine::Utils::DateCalculation
include Redmine::I18n
belongs_to :project
belongs_to :tracker
@@ -91,12 +92,15 @@ class Issue < ActiveRecord::Base
}
before_create :default_assign
before_save :close_duplicates, :update_done_ratio_from_issue_status, :force_updated_on_change, :update_closed_on
before_save :close_duplicates, :update_done_ratio_from_issue_status,
:force_updated_on_change, :update_closed_on
after_save {|issue| issue.send :after_project_change if !issue.id_changed? && issue.project_id_changed?}
after_save :reschedule_following_issues, :update_nested_set_attributes, :update_parent_attributes, :create_journal
after_save :reschedule_following_issues, :update_nested_set_attributes,
:update_parent_attributes, :create_journal
# Should be after_create but would be called before previous after_save callbacks
after_save :after_create_from_copy
after_destroy :update_parent_attributes
after_create :send_notification
# Returns a SQL conditions string used to find all issues visible by the specified user
def self.visible_condition(user, options={})
@@ -106,10 +110,10 @@ class Issue < ActiveRecord::Base
when 'all'
nil
when 'default'
user_ids = [user.id] + user.groups.map(&:id)
user_ids = [user.id] + user.groups.map(&:id).compact
"(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
when 'own'
user_ids = [user.id] + user.groups.map(&:id)
user_ids = [user.id] + user.groups.map(&:id).compact
"(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
else
'1=0'
@@ -197,6 +201,13 @@ class Issue < ActiveRecord::Base
(project && tracker) ? (project.all_issue_custom_fields & tracker.custom_fields.all) : []
end
def visible_custom_field_values(user=nil)
user_real = user || User.current
custom_field_values.select do |value|
value.custom_field.visible_by?(project, user_real)
end
end
# Copies attributes from another issue, arg can be an id or an Issue
def copy_from(arg, options={})
issue = arg.is_a?(Issue) ? arg : Issue.visible.find(arg)
@@ -347,8 +358,7 @@ class Issue < ActiveRecord::Base
if issue.new_record?
issue.copy?
elsif user.allowed_to?(:move_issues, issue.project)
projects = Issue.allowed_target_projects_on_move(user)
projects.include?(issue.project) && projects.size > 1
Issue.allowed_target_projects_on_move.count > 1
end
}
@@ -415,7 +425,7 @@ class Issue < ActiveRecord::Base
# Project and Tracker must be set before since new_statuses_allowed_to depends on it.
if (p = attrs.delete('project_id')) && safe_attribute?('project_id')
if allowed_target_projects(user).collect(&:id).include?(p.to_i)
if allowed_target_projects(user).where(:id => p.to_i).exists?
self.project_id = p
end
end
@@ -445,11 +455,15 @@ class Issue < ActiveRecord::Base
end
if attrs['custom_field_values'].present?
attrs['custom_field_values'] = attrs['custom_field_values'].reject {|k, v| read_only_attribute_names(user).include? k.to_s}
editable_custom_field_ids = editable_custom_field_values(user).map {|v| v.custom_field_id.to_s}
# TODO: use #select when ruby1.8 support is dropped
attrs['custom_field_values'] = attrs['custom_field_values'].reject {|k, v| !editable_custom_field_ids.include?(k.to_s)}
end
if attrs['custom_fields'].present?
attrs['custom_fields'] = attrs['custom_fields'].reject {|c| read_only_attribute_names(user).include? c['id'].to_s}
editable_custom_field_ids = editable_custom_field_values(user).map {|v| v.custom_field_id.to_s}
# TODO: use #select when ruby1.8 support is dropped
attrs['custom_fields'] = attrs['custom_fields'].reject {|c| !editable_custom_field_ids.include?(c['id'].to_s)}
end
# mass-assignment security bypass
@@ -462,7 +476,7 @@ class Issue < ActiveRecord::Base
# Returns the custom_field_values that can be edited by the given user
def editable_custom_field_values(user=nil)
custom_field_values.reject do |value|
visible_custom_field_values(user).reject do |value|
read_only_attribute_names(user).include?(value.custom_field_id.to_s)
end
end
@@ -547,12 +561,12 @@ class Issue < ActiveRecord::Base
end
def validate_issue
if due_date && start_date && due_date < start_date
if due_date && start_date && (start_date_changed? || due_date_changed?) && due_date < start_date
errors.add :due_date, :greater_than_start_date
end
if start_date && soonest_start && start_date < soonest_start
errors.add :start_date, :invalid
if start_date && start_date_changed? && soonest_start && start_date < soonest_start
errors.add :start_date, :earlier_than_minimum_start_date, :date => format_date(soonest_start)
end
if fixed_version
@@ -691,7 +705,7 @@ class Issue < ActiveRecord::Base
# Is the amount of work done less than it should for the due date
def behind_schedule?
return false if start_date.nil? || due_date.nil?
done_date = start_date + ((due_date - start_date+1)* done_ratio/100).floor
done_date = start_date + ((due_date - start_date + 1) * done_ratio / 100).floor
return done_date <= Date.today
end
@@ -744,12 +758,16 @@ class Issue < ActiveRecord::Base
initial_status = IssueStatus.find_by_id(status_id_was)
end
initial_status ||= status
initial_assigned_to_id = assigned_to_id_changed? ? assigned_to_id_was : assigned_to_id
assignee_transitions_allowed = initial_assigned_to_id.present? &&
(user.id == initial_assigned_to_id || user.group_ids.include?(initial_assigned_to_id))
statuses = initial_status.find_new_statuses_allowed_to(
user.admin ? Role.all : user.roles_for_project(project),
tracker,
author == user,
assigned_to_id_changed? ? assigned_to_id_was == user.id : assigned_to_id == user.id
assignee_transitions_allowed
)
statuses << initial_status unless statuses.empty?
statuses << IssueStatus.default if include_default
@@ -790,6 +808,21 @@ class Issue < ActiveRecord::Base
notified_users.collect(&:mail)
end
def each_notification(users, &block)
if users.any?
if custom_field_values.detect {|value| !value.custom_field.visible?}
users_by_custom_field_visibility = users.group_by do |user|
visible_custom_field_values(user).map(&:custom_field_id).sort
end
users_by_custom_field_visibility.values.each do |users|
yield(users)
end
else
yield(users)
end
end
end
# Returns the number of hours spent on this issue
def spent_hours
@spent_hours ||= time_entries.sum(:hours) || 0
@@ -812,7 +845,7 @@ class Issue < ActiveRecord::Base
# Preloads relations for a collection of issues
def self.load_relations(issues)
if issues.any?
relations = IssueRelation.all(:conditions => ["issue_from_id IN (:ids) OR issue_to_id IN (:ids)", {:ids => issues.map(&:id)}])
relations = IssueRelation.where("issue_from_id IN (:ids) OR issue_to_id IN (:ids)", :ids => issues.map(&:id)).all
issues.each do |issue|
issue.instance_variable_set "@relations", relations.select {|r| r.issue_from_id == issue.id || r.issue_to_id == issue.id}
end
@@ -822,7 +855,7 @@ class Issue < ActiveRecord::Base
# Preloads visible spent time for a collection of issues
def self.load_visible_spent_hours(issues, user=User.current)
if issues.any?
hours_by_issue_id = TimeEntry.visible(user).sum(:hours, :group => :issue_id)
hours_by_issue_id = TimeEntry.visible(user).group(:issue_id).sum(:hours)
issues.each do |issue|
issue.instance_variable_set "@spent_hours", (hours_by_issue_id[issue.id] || 0)
end
@@ -850,22 +883,103 @@ class Issue < ActiveRecord::Base
# Finds an issue relation given its id.
def find_relation(relation_id)
IssueRelation.find(relation_id, :conditions => ["issue_to_id = ? OR issue_from_id = ?", id, id])
IssueRelation.where("issue_to_id = ? OR issue_from_id = ?", id, id).find(relation_id)
end
# Returns all the other issues that depend on the issue
# The algorithm is a modified breadth first search (bfs)
def all_dependent_issues(except=[])
except << self
# The found dependencies
dependencies = []
dependencies += relations_from.map(&:issue_to)
dependencies += children unless leaf?
dependencies.compact!
# The visited flag for every node (issue) used by the breadth first search
eNOT_DISCOVERED = 0 # The issue is "new" to the algorithm, it has not seen it before.
ePROCESS_ALL = 1 # The issue is added to the queue. Process both children and relations of
# the issue when it is processed.
ePROCESS_RELATIONS_ONLY = 2 # The issue was added to the queue and will be output as dependent issue,
# but its children will not be added to the queue when it is processed.
eRELATIONS_PROCESSED = 3 # The related issues, the parent issue and the issue itself have been added to
# the queue, but its children have not been added.
ePROCESS_CHILDREN_ONLY = 4 # The relations and the parent of the issue have been added to the queue, but
# the children still need to be processed.
eALL_PROCESSED = 5 # The issue and all its children, its parent and its related issues have been
# added as dependent issues. It needs no further processing.
issue_status = Hash.new(eNOT_DISCOVERED)
# The queue
queue = []
# Initialize the bfs, add start node (self) to the queue
queue << self
issue_status[self] = ePROCESS_ALL
while (!queue.empty?) do
current_issue = queue.shift
current_issue_status = issue_status[current_issue]
dependencies << current_issue
# Add parent to queue, if not already in it.
parent = current_issue.parent
parent_status = issue_status[parent]
if parent && (parent_status == eNOT_DISCOVERED) && !except.include?(parent)
queue << parent
issue_status[parent] = ePROCESS_RELATIONS_ONLY
end
# Add children to queue, but only if they are not already in it and
# the children of the current node need to be processed.
if (current_issue_status == ePROCESS_CHILDREN_ONLY || current_issue_status == ePROCESS_ALL)
current_issue.children.each do |child|
next if except.include?(child)
if (issue_status[child] == eNOT_DISCOVERED)
queue << child
issue_status[child] = ePROCESS_ALL
elsif (issue_status[child] == eRELATIONS_PROCESSED)
queue << child
issue_status[child] = ePROCESS_CHILDREN_ONLY
elsif (issue_status[child] == ePROCESS_RELATIONS_ONLY)
queue << child
issue_status[child] = ePROCESS_ALL
end
end
end
# Add related issues to the queue, if they are not already in it.
current_issue.relations_from.map(&:issue_to).each do |related_issue|
next if except.include?(related_issue)
if (issue_status[related_issue] == eNOT_DISCOVERED)
queue << related_issue
issue_status[related_issue] = ePROCESS_ALL
elsif (issue_status[related_issue] == eRELATIONS_PROCESSED)
queue << related_issue
issue_status[related_issue] = ePROCESS_CHILDREN_ONLY
elsif (issue_status[related_issue] == ePROCESS_RELATIONS_ONLY)
queue << related_issue
issue_status[related_issue] = ePROCESS_ALL
end
end
# Set new status for current issue
if (current_issue_status == ePROCESS_ALL) || (current_issue_status == ePROCESS_CHILDREN_ONLY)
issue_status[current_issue] = eALL_PROCESSED
elsif (current_issue_status == ePROCESS_RELATIONS_ONLY)
issue_status[current_issue] = eRELATIONS_PROCESSED
end
end # while
# Remove the issues from the "except" parameter from the result array
dependencies -= except
dependencies += dependencies.map {|issue| issue.all_dependent_issues(except)}.flatten
if parent
dependencies << parent
dependencies += parent.all_dependent_issues(except + parent.descendants)
end
dependencies.delete(self)
dependencies
end
@@ -960,40 +1074,19 @@ class Issue < ActiveRecord::Base
end
# Returns a string of css classes that apply to the issue
def css_classes
def css_classes(user=User.current)
s = "issue tracker-#{tracker_id} status-#{status_id} #{priority.try(:css_classes)}"
s << ' closed' if closed?
s << ' overdue' if overdue?
s << ' child' if child?
s << ' parent' unless leaf?
s << ' private' if is_private?
s << ' created-by-me' if User.current.logged? && author_id == User.current.id
s << ' assigned-to-me' if User.current.logged? && assigned_to_id == User.current.id
s
end
# Saves an issue and a time_entry from the parameters
def save_issue_with_child_records(params, existing_time_entry=nil)
Issue.transaction do
if params[:time_entry] && (params[:time_entry][:hours].present? || params[:time_entry][:comments].present?) && User.current.allowed_to?(:log_time, project)
@time_entry = existing_time_entry || TimeEntry.new
@time_entry.project = project
@time_entry.issue = self
@time_entry.user = User.current
@time_entry.spent_on = User.current.today
@time_entry.attributes = params[:time_entry]
self.time_entries << @time_entry
end
# TODO: Rename hook
Redmine::Hook.call_hook(:controller_issues_edit_before_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal})
if save
# TODO: Rename hook
Redmine::Hook.call_hook(:controller_issues_edit_after_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal})
else
raise ActiveRecord::Rollback
end
if user.logged?
s << ' created-by-me' if author_id == user.id
s << ' assigned-to-me' if assigned_to_id == user.id
s << ' assigned-to-my-group' if user.groups.any? {|g| g.id = assigned_to_id}
end
s
end
# Unassigns issues from +version+ if it's no longer shared with issue's project
@@ -1014,6 +1107,10 @@ class Issue < ActiveRecord::Base
s = arg.to_s.strip.presence
if s && (m = s.match(%r{\A#?(\d+)\z})) && (@parent_issue = Issue.find_by_id(m[1]))
@parent_issue.id
@invalid_parent_issue_id = nil
elsif s.blank?
@parent_issue = nil
@invalid_parent_issue_id = nil
else
@parent_issue = nil
@invalid_parent_issue_id = arg
@@ -1102,18 +1199,18 @@ class Issue < ActiveRecord::Base
end
# End ReportsController extraction
# Returns an array of projects that user can assign the issue to
# Returns a scope of projects that user can assign the issue to
def allowed_target_projects(user=User.current)
if new_record?
Project.all(:conditions => Project.allowed_to_condition(user, :add_issues))
Project.where(Project.allowed_to_condition(user, :add_issues))
else
self.class.allowed_target_projects_on_move(user)
end
end
# Returns an array of projects that user can move issues to
# Returns a scope of projects that user can move issues to
def self.allowed_target_projects_on_move(user=User.current)
Project.all(:conditions => Project.allowed_to_condition(user, :move_issues))
Project.where(Project.allowed_to_condition(user, :move_issues))
end
private
@@ -1184,48 +1281,50 @@ class Issue < ActiveRecord::Base
# issue was just created
self.root_id = (@parent_issue.nil? ? id : @parent_issue.root_id)
set_default_left_and_right
Issue.update_all("root_id = #{root_id}, lft = #{lft}, rgt = #{rgt}", ["id = ?", id])
Issue.update_all(["root_id = ?, lft = ?, rgt = ?", root_id, lft, rgt], ["id = ?", id])
if @parent_issue
move_to_child_of(@parent_issue)
end
reload
elsif parent_issue_id != parent_id
former_parent_id = parent_id
# moving an existing issue
if @parent_issue && @parent_issue.root_id == root_id
# inside the same tree
move_to_child_of(@parent_issue)
else
# to another tree
unless root?
move_to_right_of(root)
reload
end
old_root_id = root_id
self.root_id = (@parent_issue.nil? ? id : @parent_issue.root_id )
target_maxright = nested_set_scope.maximum(right_column_name) || 0
offset = target_maxright + 1 - lft
Issue.update_all("root_id = #{root_id}, lft = lft + #{offset}, rgt = rgt + #{offset}",
["root_id = ? AND lft >= ? AND rgt <= ? ", old_root_id, lft, rgt])
self[left_column_name] = lft + offset
self[right_column_name] = rgt + offset
if @parent_issue
move_to_child_of(@parent_issue)
end
end
reload
# delete invalid relations of all descendants
self_and_descendants.each do |issue|
issue.relations.each do |relation|
relation.destroy unless relation.valid?
end
end
# update former parent
recalculate_attributes_for(former_parent_id) if former_parent_id
update_nested_set_attributes_on_parent_change
end
remove_instance_variable(:@parent_issue) if instance_variable_defined?(:@parent_issue)
end
# Updates the nested set for when an existing issue is moved
def update_nested_set_attributes_on_parent_change
former_parent_id = parent_id
# moving an existing issue
if @parent_issue && @parent_issue.root_id == root_id
# inside the same tree
move_to_child_of(@parent_issue)
else
# to another tree
unless root?
move_to_right_of(root)
end
old_root_id = root_id
self.root_id = (@parent_issue.nil? ? id : @parent_issue.root_id )
target_maxright = nested_set_scope.maximum(right_column_name) || 0
offset = target_maxright + 1 - lft
Issue.update_all(["root_id = ?, lft = lft + ?, rgt = rgt + ?", root_id, offset, offset],
["root_id = ? AND lft >= ? AND rgt <= ? ", old_root_id, lft, rgt])
self[left_column_name] = lft + offset
self[right_column_name] = rgt + offset
if @parent_issue
move_to_child_of(@parent_issue)
end
end
# delete invalid relations of all descendants
self_and_descendants.each do |issue|
issue.relations.each do |relation|
relation.destroy unless relation.valid?
end
end
# update former parent
recalculate_attributes_for(former_parent_id) if former_parent_id
end
def update_parent_attributes
recalculate_attributes_for(parent_id) if parent_id
end
@@ -1252,7 +1351,8 @@ class Issue < ActiveRecord::Base
if average == 0
average = 1
end
done = p.leaves.sum("COALESCE(estimated_hours, #{average}) * (CASE WHEN is_closed = #{connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)", :joins => :status).to_f
done = p.leaves.sum("COALESCE(CASE WHEN estimated_hours > 0 THEN estimated_hours ELSE NULL END, #{average}) " +
"* (CASE WHEN is_closed = #{connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)", :joins => :status).to_f
progress = done / (average * leaves_count)
p.done_ratio = progress.round
end
@@ -1272,12 +1372,11 @@ class Issue < ActiveRecord::Base
def self.update_versions(conditions=nil)
# Only need to update issues with a fixed_version from
# a different project and that is not systemwide shared
Issue.scoped(:conditions => conditions).all(
:conditions => "#{Issue.table_name}.fixed_version_id IS NOT NULL" +
Issue.includes(:project, :fixed_version).
where("#{Issue.table_name}.fixed_version_id IS NOT NULL" +
" AND #{Issue.table_name}.project_id <> #{Version.table_name}.project_id" +
" AND #{Version.table_name}.sharing <> 'system'",
:include => [:project, :fixed_version]
).each do |issue|
" AND #{Version.table_name}.sharing <> 'system'").
where(conditions).each do |issue|
next if issue.project.nil? || issue.fixed_version.nil?
unless issue.project.shared_versions.include?(issue.fixed_version)
issue.init_journal(User.current)
@@ -1410,6 +1509,12 @@ class Issue < ActiveRecord::Base
end
end
def send_notification
if Setting.notified_events.include?('issue_added')
Mailer.deliver_issue_add(self)
end
end
# Query generator for selecting groups of issue counts for a project
# based on specific criteria
#

View File

@@ -23,5 +23,22 @@ class IssueCustomField < CustomField
def type_name
:label_issue_plural
end
end
def visible_by?(project, user=User.current)
super || (roles & user.roles_for_project(project)).present?
end
def visibility_by_project_condition(*args)
sql = super
additional_sql = "#{Issue.table_name}.tracker_id IN (SELECT tracker_id FROM #{table_name_prefix}custom_fields_trackers#{table_name_suffix} WHERE custom_field_id = #{id})"
unless is_for_all?
additional_sql << " AND #{Issue.table_name}.project_id IN (SELECT project_id FROM #{table_name_prefix}custom_fields_projects#{table_name_suffix} WHERE custom_field_id = #{id})"
end
"((#{sql}) AND (#{additional_sql}))"
end
def validate_custom_field
super
errors.add(:base, l(:label_role_plural) + ' ' + l('activerecord.errors.messages.blank')) unless visible? || roles.present?
end
end

View File

@@ -1,22 +0,0 @@
# Redmine - project management software
# Copyright (C) 2006-2013 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.
class IssueObserver < ActiveRecord::Observer
def after_create(issue)
Mailer.issue_add(issue).deliver if Setting.notified_events.include?('issue_added')
end
end

View File

@@ -45,9 +45,25 @@ class IssueQuery < Query
scope :visible, lambda {|*args|
user = args.shift || User.current
base = Project.allowed_to_condition(user, :view_issues, *args)
user_id = user.logged? ? user.id : 0
scope = includes(:project).where("#{table_name}.project_id IS NULL OR (#{base})")
includes(:project).where("(#{table_name}.project_id IS NULL OR (#{base})) AND (#{table_name}.is_public = ? OR #{table_name}.user_id = ?)", true, user_id)
if user.admin?
scope.where("#{table_name}.visibility <> ? OR #{table_name}.user_id = ?", VISIBILITY_PRIVATE, user.id)
elsif user.memberships.any?
scope.where("#{table_name}.visibility = ?" +
" OR (#{table_name}.visibility = ? AND #{table_name}.id IN (" +
"SELECT DISTINCT q.id FROM #{table_name} q" +
" INNER JOIN #{table_name_prefix}queries_roles#{table_name_suffix} qr on qr.query_id = q.id" +
" INNER JOIN #{MemberRole.table_name} mr ON mr.role_id = qr.role_id" +
" INNER JOIN #{Member.table_name} m ON m.id = mr.member_id AND m.user_id = ?" +
" WHERE q.project_id IS NULL OR q.project_id = m.project_id))" +
" OR #{table_name}.user_id = ?",
VISIBILITY_PUBLIC, VISIBILITY_ROLES, user.id, user.id)
elsif user.logged?
scope.where("#{table_name}.visibility = ? OR #{table_name}.user_id = ?", VISIBILITY_PUBLIC, user.id)
else
scope.where("#{table_name}.visibility = ?", VISIBILITY_PUBLIC)
end
}
def initialize(attributes=nil, *args)
@@ -57,7 +73,53 @@ class IssueQuery < Query
# Returns true if the query is visible to +user+ or the current user.
def visible?(user=User.current)
(project.nil? || user.allowed_to?(:view_issues, project)) && (self.is_public? || self.user_id == user.id)
return true if user.admin?
return false unless project.nil? || user.allowed_to?(:view_issues, project)
case visibility
when VISIBILITY_PUBLIC
true
when VISIBILITY_ROLES
if project
(user.roles_for_project(project) & roles).any?
else
Member.where(:user_id => user.id).joins(:roles).where(:member_roles => {:role_id => roles.map(&:id)}).any?
end
else
user == self.user
end
end
def is_private?
visibility == VISIBILITY_PRIVATE
end
def is_public?
!is_private?
end
def draw_relations
r = options[:draw_relations]
r.nil? || r == '1'
end
def draw_relations=(arg)
options[:draw_relations] = (arg == '0' ? '0' : nil)
end
def draw_progress_line
r = options[:draw_progress_line]
r == '1'
end
def draw_progress_line=(arg)
options[:draw_progress_line] = (arg == '1' ? '1' : nil)
end
def build_from_params(params)
super
self.draw_relations = params[:draw_relations] || (params[:query] && params[:query][:draw_relations])
self.draw_progress_line = params[:draw_progress_line] || (params[:query] && params[:query][:draw_progress_line])
self
end
def initialize_available_filters
@@ -66,7 +128,7 @@ class IssueQuery < Query
versions = []
categories = []
issue_custom_fields = []
if project
principals += project.principals.sort
unless project.leaf?
@@ -81,13 +143,12 @@ class IssueQuery < Query
principals += Principal.member_of(all_projects)
end
versions = Version.visible.find_all_by_sharing('system')
issue_custom_fields = IssueCustomField.where(:is_filter => true, :is_for_all => true).all
issue_custom_fields = IssueCustomField.where(:is_for_all => true)
end
principals.uniq!
principals.sort!
users = principals.select {|p| p.is_a?(User)}
add_available_filter "status_id",
:type => :list_status, :values => IssueStatus.sorted.all.collect{|s| [s.name, s.id.to_s] }
@@ -189,8 +250,8 @@ class IssueQuery < Query
@available_columns = self.class.available_columns.dup
@available_columns += (project ?
project.all_issue_custom_fields :
IssueCustomField.all
).collect {|cf| QueryCustomFieldColumn.new(cf) }
IssueCustomField
).visible.collect {|cf| QueryCustomFieldColumn.new(cf) }
if User.current.allowed_to?(:view_time_entries, project, :global => true)
index = nil
@@ -227,7 +288,7 @@ class IssueQuery < Query
# Returns the issue count
def issue_count
Issue.visible.count(:include => [:status, :project], :conditions => statement)
Issue.visible.joins(:status, :project).where(statement).count
rescue ::ActiveRecord::StatementInvalid => e
raise StatementInvalid.new(e.message)
end
@@ -238,7 +299,12 @@ class IssueQuery < Query
if grouped?
begin
# Rails3 will raise an (unexpected) RecordNotFound if there's only a nil group value
r = Issue.visible.count(:joins => joins_for_order_statement(group_by_statement), :group => group_by_statement, :include => [:status, :project], :conditions => statement)
r = Issue.visible.
joins(:status, :project).
where(statement).
joins(joins_for_order_statement(group_by_statement)).
group(group_by_statement).
count
rescue ActiveRecord::RecordNotFound
r = {nil => issue_count}
end
@@ -257,14 +323,21 @@ class IssueQuery < Query
def issues(options={})
order_option = [group_by_sort_order, options[:order]].flatten.reject(&:blank?)
issues = Issue.visible.where(options[:conditions]).all(
:include => ([:status, :project] + (options[:include] || [])).uniq,
:conditions => statement,
:order => order_option,
:joins => joins_for_order_statement(order_option.join(',')),
:limit => options[:limit],
:offset => options[:offset]
)
scope = Issue.visible.
joins(:status, :project).
where(statement).
includes(([:status, :project] + (options[:include] || [])).uniq).
where(options[:conditions]).
order(order_option).
joins(joins_for_order_statement(order_option.join(','))).
limit(options[:limit]).
offset(options[:offset])
if has_custom_field_column?
scope = scope.preload(:custom_values)
end
issues = scope.all
if has_column?(:spent_hours)
Issue.load_visible_spent_hours(issues)
@@ -281,12 +354,16 @@ class IssueQuery < Query
def issue_ids(options={})
order_option = [group_by_sort_order, options[:order]].flatten.reject(&:blank?)
Issue.visible.scoped(:conditions => options[:conditions]).scoped(:include => ([:status, :project] + (options[:include] || [])).uniq,
:conditions => statement,
:order => order_option,
:joins => joins_for_order_statement(order_option.join(',')),
:limit => options[:limit],
:offset => options[:offset]).find_ids
Issue.visible.
joins(:status, :project).
where(statement).
includes(([:status, :project] + (options[:include] || [])).uniq).
where(options[:conditions]).
order(order_option).
joins(joins_for_order_statement(order_option.join(','))).
limit(options[:limit]).
offset(options[:offset]).
find_ids
rescue ::ActiveRecord::StatementInvalid => e
raise StatementInvalid.new(e.message)
end
@@ -294,13 +371,14 @@ class IssueQuery < Query
# Returns the journals
# Valid options are :order, :offset, :limit
def journals(options={})
Journal.visible.all(
:include => [:details, :user, {:issue => [:project, :author, :tracker, :status]}],
:conditions => statement,
:order => options[:order],
:limit => options[:limit],
:offset => options[:offset]
)
Journal.visible.
joins(:issue => [:project, :status]).
where(statement).
order(options[:order]).
limit(options[:limit]).
offset(options[:offset]).
preload(:details, :user, {:issue => [:project, :author, :tracker, :status]}).
all
rescue ::ActiveRecord::StatementInvalid => e
raise StatementInvalid.new(e.message)
end
@@ -308,10 +386,11 @@ class IssueQuery < Query
# Returns the versions
# Valid options are :conditions
def versions(options={})
Version.visible.where(options[:conditions]).all(
:include => :project,
:conditions => project_statement
)
Version.visible.
where(project_statement).
where(options[:conditions]).
includes(:project).
all
rescue ::ActiveRecord::StatementInvalid => e
raise StatementInvalid.new(e.message)
end
@@ -393,10 +472,9 @@ class IssueQuery < Query
if relation_options[:sym] == field && !options[:reverse]
sqls = [sql, sql_for_relations(field, operator, value, :reverse => true)]
sqls.join(["!", "!*", "!p"].include?(operator) ? " AND " : " OR ")
else
sql
sql = sqls.join(["!", "!*", "!p"].include?(operator) ? " AND " : " OR ")
end
"(#{sql})"
end
IssueRelation::TYPES.keys.each do |relation_type|

View File

@@ -72,6 +72,8 @@ class IssueRelation < ActiveRecord::Base
attr_protected :issue_from_id, :issue_to_id
before_save :handle_issue_order
after_create :create_journal_after_create
after_destroy :create_journal_after_delete
def visible?(user=User.current)
(issue_from.nil? || issue_from.visible?(user)) && (issue_to.nil? || issue_to.visible?(user))
@@ -179,4 +181,30 @@ class IssueRelation < ActiveRecord::Base
self.relation_type = TYPES[relation_type][:reverse]
end
end
def create_journal_after_create
journal = issue_from.init_journal(User.current)
journal.details << JournalDetail.new(:property => 'relation',
:prop_key => label_for(issue_from).to_s,
:value => issue_to.id)
journal.save
journal = issue_to.init_journal(User.current)
journal.details << JournalDetail.new(:property => 'relation',
:prop_key => label_for(issue_to).to_s,
:value => issue_from.id)
journal.save
end
def create_journal_after_delete
journal = issue_from.init_journal(User.current)
journal.details << JournalDetail.new(:property => 'relation',
:prop_key => label_for(issue_from).to_s,
:old_value => issue_to.id)
journal.save
journal = issue_to.init_journal(User.current)
journal.details << JournalDetail.new(:property => 'relation',
:prop_key => label_for(issue_to).to_s,
:old_value => issue_from.id)
journal.save
end
end

View File

@@ -39,6 +39,7 @@ class Journal < ActiveRecord::Base
" (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')"}
before_create :split_private_notes
after_create :send_notification
scope :visible, lambda {|*args|
user = args.shift || User.current
@@ -53,6 +54,32 @@ class Journal < ActiveRecord::Base
(details.empty? && notes.blank?) ? false : super
end
# Returns journal details that are visible to user
def visible_details(user=User.current)
details.select do |detail|
if detail.property == 'cf'
detail.custom_field && detail.custom_field.visible_by?(project, user)
elsif detail.property == 'relation'
Issue.find_by_id(detail.value || detail.old_value).try(:visible?, user)
else
true
end
end
end
def each_notification(users, &block)
if users.any?
users_by_details_visibility = users.group_by do |user|
visible_details(user)
end
users_by_details_visibility.each do |visible_details, users|
if notes? || visible_details.any?
yield(users)
end
end
end
end
# Returns the new status if the journal contains a status change, otherwise nil
def new_status
c = details.detect {|detail| detail.prop_key == 'status_id'}
@@ -93,20 +120,44 @@ class Journal < ActiveRecord::Base
@notify = arg
end
def recipients
def notified_users
notified = journalized.notified_users
if private_notes?
notified = notified.select {|user| user.allowed_to?(:view_private_notes, journalized.project)}
end
notified.map(&:mail)
notified
end
def watcher_recipients
def recipients
notified_users.map(&:mail)
end
def notified_watchers
notified = journalized.notified_watchers
if private_notes?
notified = notified.select {|user| user.allowed_to?(:view_private_notes, journalized.project)}
end
notified.map(&:mail)
notified
end
def watcher_recipients
notified_watchers.map(&:mail)
end
# Sets @custom_field instance variable on journals details using a single query
def self.preload_journals_details_custom_fields(journals)
field_ids = journals.map(&:details).flatten.select {|d| d.property == 'cf'}.map(&:prop_key).uniq
if field_ids.any?
fields_by_id = CustomField.find_all_by_id(field_ids).inject({}) {|h, f| h[f.id] = f; h}
journals.each do |journal|
journal.details.each do |detail|
if detail.property == 'cf'
detail.instance_variable_set "@custom_field", fields_by_id[detail.prop_key.to_i]
end
end
end
end
journals
end
private
@@ -129,4 +180,14 @@ class Journal < ActiveRecord::Base
end
true
end
def send_notification
if notify? && (Setting.notified_events.include?('issue_updated') ||
(Setting.notified_events.include?('issue_note_added') && notes.present?) ||
(Setting.notified_events.include?('issue_status_updated') && new_status.present?) ||
(Setting.notified_events.include?('issue_priority_updated') && new_value_for('priority_id').present?)
)
Mailer.deliver_issue_edit(self)
end
end
end

View File

@@ -19,6 +19,12 @@ class JournalDetail < ActiveRecord::Base
belongs_to :journal
before_save :normalize_values
def custom_field
if property == 'cf'
@custom_field ||= CustomField.find_by_id(prop_key)
end
end
private
def normalize_values

View File

@@ -1,29 +0,0 @@
# Redmine - project management software
# Copyright (C) 2006-2013 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.
class JournalObserver < ActiveRecord::Observer
def after_create(journal)
if journal.notify? &&
(Setting.notified_events.include?('issue_updated') ||
(Setting.notified_events.include?('issue_note_added') && journal.notes.present?) ||
(Setting.notified_events.include?('issue_status_updated') && journal.new_status.present?) ||
(Setting.notified_events.include?('issue_priority_updated') && journal.new_value_for('priority_id').present?)
)
Mailer.issue_edit(journal).deliver
end
end
end

View File

@@ -46,6 +46,19 @@ class MailHandler < ActionMailer::Base
super(email)
end
# Extracts MailHandler options from environment variables
# Use when receiving emails with rake tasks
def self.extract_options_from_env(env)
options = {:issue => {}}
%w(project status tracker category priority).each do |option|
options[:issue][option.to_sym] = env[option] if env[option]
end
%w(allow_override unknown_user no_permission_check no_account_notice default_group).each do |option|
options[option.to_sym] = env[option] if env[option]
end
options
end
def logger
Rails.logger
end
@@ -63,7 +76,7 @@ class MailHandler < ActionMailer::Base
sender_email = email.from.to_a.first.to_s.strip
# Ignore emails received from the application emission address to avoid hell cycles
if sender_email.downcase == Setting.mail_from.to_s.strip.downcase
if logger && logger.info
if logger
logger.info "MailHandler: ignoring email from Redmine emission address [#{sender_email}]"
end
return false
@@ -74,7 +87,7 @@ class MailHandler < ActionMailer::Base
if value
value = value.to_s.downcase
if (ignored_value.is_a?(Regexp) && value.match(ignored_value)) || value == ignored_value
if logger && logger.info
if logger
logger.info "MailHandler: ignoring email with #{key}:#{value} header"
end
return false
@@ -83,7 +96,7 @@ class MailHandler < ActionMailer::Base
end
@user = User.find_by_mail(sender_email) if sender_email.present?
if @user && !@user.active?
if logger && logger.info
if logger
logger.info "MailHandler: ignoring email from non-active user [#{@user.login}]"
end
return false
@@ -96,7 +109,7 @@ class MailHandler < ActionMailer::Base
when 'create'
@user = create_user_from_email
if @user
if logger && logger.info
if logger
logger.info "MailHandler: [#{@user.login}] account created"
end
add_user_to_group(@@handler_options[:default_group])
@@ -104,14 +117,14 @@ class MailHandler < ActionMailer::Base
Mailer.account_information(@user, @user.password).deliver
end
else
if logger && logger.error
if logger
logger.error "MailHandler: could not create account for [#{sender_email}]"
end
return false
end
else
# Default behaviour, emails from unknown users are ignored
if logger && logger.info
if logger
logger.info "MailHandler: ignoring email from unknown user [#{sender_email}]"
end
return false
@@ -123,7 +136,7 @@ class MailHandler < ActionMailer::Base
private
MESSAGE_ID_RE = %r{^<?redmine\.([a-z0-9_]+)\-(\d+)\.\d+@}
MESSAGE_ID_RE = %r{^<?redmine\.([a-z0-9_]+)\-(\d+)\.\d+(\.[a-f0-9]+)?@}
ISSUE_REPLY_SUBJECT_RE = %r{\[[^\]]*#(\d+)\]}
MESSAGE_REPLY_SUBJECT_RE = %r{\[[^\]]*msg(\d+)\]}
@@ -182,7 +195,7 @@ class MailHandler < ActionMailer::Base
add_watchers(issue)
issue.save!
add_attachments(issue)
logger.info "MailHandler: issue ##{issue.id} created by #{user}" if logger && logger.info
logger.info "MailHandler: issue ##{issue.id} created by #{user}" if logger
issue
end
@@ -211,7 +224,7 @@ class MailHandler < ActionMailer::Base
journal.notes = cleaned_up_text_body
add_attachments(issue)
issue.save!
if logger && logger.info
if logger
logger.info "MailHandler: issue ##{issue.id} updated by #{user}"
end
journal
@@ -244,7 +257,7 @@ class MailHandler < ActionMailer::Base
add_attachments(reply)
reply
else
if logger && logger.info
if logger
logger.info "MailHandler: ignoring reply from [#{sender_email}] to a locked topic"
end
end
@@ -254,6 +267,7 @@ class MailHandler < ActionMailer::Base
def add_attachments(obj)
if email.attachments && email.attachments.any?
email.attachments.each do |attachment|
next unless accept_attachment?(attachment)
obj.attachments << Attachment.create(:container => obj,
:file => attachment.decoded,
:filename => attachment.filename,
@@ -263,6 +277,19 @@ class MailHandler < ActionMailer::Base
end
end
# Returns false if the +attachment+ of the incoming email should be ignored
def accept_attachment?(attachment)
@excluded ||= Setting.mail_handler_excluded_filenames.to_s.split(',').map(&:strip).reject(&:blank?)
@excluded.each do |pattern|
regexp = %r{\A#{Regexp.escape(pattern).gsub("\\*", ".*")}\z}i
if attachment.filename.to_s =~ regexp
logger.info "MailHandler: ignoring attachment #{attachment.filename} matching #{pattern}"
return false
end
end
true
end
# Adds To and Cc as watchers of the given object if the sender has the
# appropriate permission
def add_watchers(obj)
@@ -320,6 +347,13 @@ class MailHandler < ActionMailer::Base
# * parse the email To field
# * specific project (eg. Setting.mail_handler_target_project)
target = Project.find_by_identifier(get_keyword(:project))
if target.nil?
# Invalid project keyword, use the project specified as the default one
default_project = @@handler_options[:issue][:project]
if default_project.present?
target = Project.find_by_identifier(default_project)
end
end
raise MissingInformation.new('Unable to determine target project') if target.nil?
target
end
@@ -364,12 +398,21 @@ class MailHandler < ActionMailer::Base
def plain_text_body
return @plain_text_body unless @plain_text_body.nil?
part = email.text_part || email.html_part || email
@plain_text_body = Redmine::CodesetUtil.to_utf8(part.body.decoded, part.charset)
parts = if (text_parts = email.all_parts.select {|p| p.mime_type == 'text/plain'}).present?
text_parts
elsif (html_parts = email.all_parts.select {|p| p.mime_type == 'text/html'}).present?
html_parts
else
[email]
end
@plain_text_body = parts.map {|p| Redmine::CodesetUtil.to_utf8(p.body.decoded, p.charset)}.join("\r\n")
# strip html tags and remove doctype directive
@plain_text_body = strip_tags(@plain_text_body.strip)
@plain_text_body.sub! %r{^<!DOCTYPE .*$}, ''
if parts.any? {|p| p.mime_type == 'text/html'}
@plain_text_body = strip_tags(@plain_text_body.strip)
@plain_text_body.sub! %r{^<!DOCTYPE .*$}, ''
end
@plain_text_body
end
@@ -404,10 +447,8 @@ class MailHandler < ActionMailer::Base
assign_string_attribute_with_limit(user, 'firstname', names.shift, 30)
assign_string_attribute_with_limit(user, 'lastname', names.join(' '), 30)
user.lastname = '-' if user.lastname.blank?
password_length = [Setting.password_min_length.to_i, 10].max
user.password = Redmine::Utils.random_hex(password_length / 2 + 1)
user.language = Setting.default_language
user.generate_password = true
user.mail_notification = 'only_my_events'
unless user.valid?
@@ -444,7 +485,7 @@ class MailHandler < ActionMailer::Base
end
end
# Adds the newly created user to default group
# Adds the newly created user to default group
def add_user_to_group(default_group)
if default_group.present?
default_group.split(',').each do |group_name|

View File

@@ -27,34 +27,35 @@ class Mailer < ActionMailer::Base
{ :host => Setting.host_name, :protocol => Setting.protocol }
end
# Builds a Mail::Message object used to email recipients of the added issue.
#
# Example:
# issue_add(issue) => Mail::Message object
# Mailer.issue_add(issue).deliver => sends an email to issue recipients
def issue_add(issue)
# Builds a mail for notifying to_users and cc_users about a new issue
def issue_add(issue, to_users, cc_users)
redmine_headers 'Project' => issue.project.identifier,
'Issue-Id' => issue.id,
'Issue-Author' => issue.author.login
redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
message_id issue
references issue
@author = issue.author
@issue = issue
@users = to_users + cc_users
@issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue)
recipients = issue.recipients
cc = issue.watcher_recipients - recipients
mail :to => recipients,
:cc => cc,
mail :to => to_users.map(&:mail),
:cc => cc_users.map(&:mail),
:subject => "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
end
# Builds a Mail::Message object used to email recipients of the edited issue.
#
# Example:
# issue_edit(journal) => Mail::Message object
# Mailer.issue_edit(journal).deliver => sends an email to issue recipients
def issue_edit(journal)
issue = journal.journalized.reload
# Notifies users about a new issue
def self.deliver_issue_add(issue)
to = issue.notified_users
cc = issue.notified_watchers - to
issue.each_notification(to + cc) do |users|
Mailer.issue_add(issue, to & users, cc & users).deliver
end
end
# Builds a mail for notifying to_users and cc_users about an issue update
def issue_edit(journal, to_users, cc_users)
issue = journal.journalized
redmine_headers 'Project' => issue.project.identifier,
'Issue-Id' => issue.id,
'Issue-Author' => issue.author.login
@@ -62,20 +63,31 @@ class Mailer < ActionMailer::Base
message_id journal
references issue
@author = journal.user
recipients = journal.recipients
# Watchers in cc
cc = journal.watcher_recipients - recipients
s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
s << issue.subject
@issue = issue
@users = to_users + cc_users
@journal = journal
@journal_details = journal.visible_details(@users.first)
@issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}")
mail :to => recipients,
:cc => cc,
mail :to => to_users.map(&:mail),
:cc => cc_users.map(&:mail),
:subject => s
end
# Notifies users about an issue update
def self.deliver_issue_edit(journal)
issue = journal.journalized.reload
to = journal.notified_users
cc = journal.notified_watchers
journal.each_notification(to + cc) do |users|
issue.each_notification(users) do |users2|
Mailer.issue_edit(journal, to & users2, cc & users2).deliver
end
end
end
def reminder(user, issues, days)
set_language_if_valid user.language
@issues = issues
@@ -142,6 +154,7 @@ class Mailer < ActionMailer::Base
redmine_headers 'Project' => news.project.identifier
@author = news.author
message_id news
references news
@news = news
@news_url = url_for(:controller => 'news', :action => 'show', :id => news)
mail :to => news.recipients,
@@ -158,6 +171,7 @@ class Mailer < ActionMailer::Base
redmine_headers 'Project' => news.project.identifier
@author = comment.author
message_id comment
references news
@news = news
@comment = comment
@news_url = url_for(:controller => 'news', :action => 'show', :id => news)
@@ -176,7 +190,7 @@ class Mailer < ActionMailer::Base
'Topic-Id' => (message.parent_id || message.id)
@author = message.author
message_id message
references message.parent unless message.parent.nil?
references message.root
recipients = message.recipients
cc = ((message.root.watcher_recipients + message.board.watcher_recipients).uniq - recipients)
@message = message
@@ -297,31 +311,6 @@ class Mailer < ActionMailer::Base
:subject => 'Redmine test'
end
# Overrides default deliver! method to prevent from sending an email
# with no recipient, cc or bcc
def deliver!(mail = @mail)
set_language_if_valid @initial_language
return false if (recipients.nil? || recipients.empty?) &&
(cc.nil? || cc.empty?) &&
(bcc.nil? || bcc.empty?)
# Log errors when raise_delivery_errors is set to false, Rails does not
raise_errors = self.class.raise_delivery_errors
self.class.raise_delivery_errors = true
begin
return super(mail)
rescue Exception => e
if raise_errors
raise e
elsif mylogger
mylogger.error "The following error occured while sending email notification: \"#{e.message}\". Check your configuration in config/configuration.yml."
end
ensure
self.class.raise_delivery_errors = raise_errors
end
end
# Sends reminders to issue assignees
# Available options:
# * :days => how many days in the future to remind about (defaults to 7)
@@ -379,7 +368,7 @@ class Mailer < ActionMailer::Base
ActionMailer::Base.delivery_method = saved_method
end
def mail(headers={})
def mail(headers={}, &block)
headers.merge! 'X-Mailer' => 'Redmine',
'X-Redmine-Host' => Setting.host_name,
'X-Redmine-Site' => Setting.app_title,
@@ -389,8 +378,9 @@ class Mailer < ActionMailer::Base
'List-Id' => "<#{Setting.mail_from.to_s.gsub('@', '.')}>"
# Removes the author from the recipients and cc
# if he doesn't want to receive notifications about what he does
if @author && @author.logged? && @author.pref[:no_self_notified]
# if the author does not want to receive notifications
# about what the author do
if @author && @author.logged? && @author.pref.no_self_notified
headers[:to].delete(@author.mail) if headers[:to].is_a?(Array)
headers[:cc].delete(@author.mail) if headers[:cc].is_a?(Array)
end
@@ -410,15 +400,20 @@ class Mailer < ActionMailer::Base
headers[:message_id] = "<#{self.class.message_id_for(@message_id_object)}>"
end
if @references_objects
headers[:references] = @references_objects.collect {|o| "<#{self.class.message_id_for(o)}>"}.join(' ')
headers[:references] = @references_objects.collect {|o| "<#{self.class.references_for(o)}>"}.join(' ')
end
super headers do |format|
format.text
format.html unless Setting.plain_text_mail?
m = if block_given?
super headers, &block
else
super headers do |format|
format.text
format.html unless Setting.plain_text_mail?
end
end
set_language_if_valid @initial_language
m
end
def initialize(*args)
@@ -426,10 +421,20 @@ class Mailer < ActionMailer::Base
set_language_if_valid Setting.default_language
super
end
def self.deliver_mail(mail)
return false if mail.to.blank? && mail.cc.blank? && mail.bcc.blank?
super
begin
# Log errors when raise_delivery_errors is set to false, Rails does not
mail.raise_delivery_errors = true
super
rescue Exception => e
if ActionMailer::Base.raise_delivery_errors
raise e
else
Rails.logger.error "Email delivery error: #{e.message}"
end
end
end
def self.method_missing(method, *args, &block)
@@ -448,15 +453,30 @@ class Mailer < ActionMailer::Base
h.each { |k,v| headers["X-Redmine-#{k}"] = v.to_s }
end
# Returns a predictable Message-Id for the given object
def self.message_id_for(object)
# id + timestamp should reduce the odds of a collision
# as far as we don't send multiple emails for the same object
def self.token_for(object, rand=true)
timestamp = object.send(object.respond_to?(:created_on) ? :created_on : :updated_on)
hash = "redmine.#{object.class.name.demodulize.underscore}-#{object.id}.#{timestamp.strftime("%Y%m%d%H%M%S")}"
hash = [
"redmine",
"#{object.class.name.demodulize.underscore}-#{object.id}",
timestamp.strftime("%Y%m%d%H%M%S")
]
if rand
hash << Redmine::Utils.random_hex(8)
end
host = Setting.mail_from.to_s.gsub(%r{^.*@}, '')
host = "#{::Socket.gethostname}.redmine" if host.empty?
"#{hash}@#{host}"
"#{hash.join('.')}@#{host}"
end
# Returns a Message-Id for the given object
def self.message_id_for(object)
token_for(object, true)
end
# Returns a uniq token for a given object referenced by all notifications
# related to this object
def self.references_for(object)
token_for(object, false)
end
def message_id(object)

View File

@@ -45,6 +45,7 @@ class Message < ActiveRecord::Base
after_create :add_author_as_watcher, :reset_counters!
after_update :update_messages_board
after_destroy :reset_counters!
after_create :send_notification
scope :visible, lambda {|*args|
includes(:board => :project).where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args))
@@ -105,4 +106,10 @@ class Message < ActiveRecord::Base
def add_author_as_watcher
Watcher.create(:watchable => self.root, :user => author)
end
def send_notification
if Setting.notified_events.include?('message_posted')
Mailer.message_posted(self).deliver
end
end
end

View File

@@ -1,22 +0,0 @@
# Redmine - project management software
# Copyright (C) 2006-2013 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.
class MessageObserver < ActiveRecord::Observer
def after_create(message)
Mailer.message_posted(message).deliver if Setting.notified_events.include?('message_posted')
end
end

View File

@@ -33,6 +33,7 @@ class News < ActiveRecord::Base
acts_as_watchable
after_create :add_author_as_watcher
after_create :send_notification
scope :visible, lambda {|*args|
includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_news, *args))
@@ -63,4 +64,10 @@ class News < ActiveRecord::Base
def add_author_as_watcher
Watcher.create(:watchable => self, :user => author)
end
def send_notification
if Setting.notified_events.include?('news_added')
Mailer.news_added(self).deliver
end
end
end

View File

@@ -33,8 +33,6 @@ class Project < ActiveRecord::Base
has_many :member_principals, :class_name => 'Member',
:include => :principal,
:conditions => "#{Principal.table_name}.type='Group' OR (#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE})"
has_many :users, :through => :members
has_many :principals, :through => :member_principals, :source => :principal
has_many :enabled_modules, :dependent => :delete_all
has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position"
@@ -92,7 +90,7 @@ class Project < ActiveRecord::Base
scope :status, lambda {|arg| where(arg.blank? ? nil : {:status => arg.to_i}) }
scope :all_public, lambda { where(:is_public => true) }
scope :visible, lambda {|*args| where(Project.visible_condition(args.shift || User.current, *args)) }
scope :allowed_to, lambda {|*args|
scope :allowed_to, lambda {|*args|
user = User.current
permission = nil
if args.first.is_a?(Symbol)
@@ -188,7 +186,7 @@ class Project < ActiveRecord::Base
else
statement_by_role = {}
unless options[:member]
role = user.logged? ? Role.non_member : Role.anonymous
role = user.builtin_role
if role.allowed_to?(permission)
statement_by_role[role] = "#{Project.table_name}.is_public = #{connection.quoted_true}"
end
@@ -215,6 +213,14 @@ class Project < ActiveRecord::Base
end
end
def principals
@principals ||= Principal.active.joins(:members).where("#{Member.table_name}.project_id = ?", id).uniq
end
def users
@users ||= User.active.joins(:members).where("#{Member.table_name}.project_id = ?", id).uniq
end
# Returns the Systemwide and project specific activities
def activities(include_inactive=false)
if include_inactive
@@ -287,6 +293,8 @@ class Project < ActiveRecord::Base
alias :base_reload :reload
def reload(*args)
@principals = nil
@users = nil
@shared_versions = nil
@rolled_up_versions = nil
@rolled_up_trackers = nil
@@ -443,26 +451,29 @@ class Project < ActiveRecord::Base
# Returns a scope of the Versions on subprojects
def rolled_up_versions
@rolled_up_versions ||=
Version.scoped(:include => :project,
:conditions => ["#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status <> #{STATUS_ARCHIVED}", lft, rgt])
Version.
includes(:project).
where("#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status <> ?", lft, rgt, STATUS_ARCHIVED)
end
# Returns a scope of the Versions used by the project
def shared_versions
if new_record?
Version.scoped(:include => :project,
:conditions => "#{Project.table_name}.status <> #{Project::STATUS_ARCHIVED} AND #{Version.table_name}.sharing = 'system'")
Version.
includes(:project).
where("#{Project.table_name}.status <> ? AND #{Version.table_name}.sharing = 'system'", STATUS_ARCHIVED)
else
@shared_versions ||= begin
r = root? ? self : root
Version.scoped(:include => :project,
:conditions => "#{Project.table_name}.id = #{id}" +
" OR (#{Project.table_name}.status <> #{Project::STATUS_ARCHIVED} AND (" +
" #{Version.table_name}.sharing = 'system'" +
" OR (#{Project.table_name}.lft >= #{r.lft} AND #{Project.table_name}.rgt <= #{r.rgt} AND #{Version.table_name}.sharing = 'tree')" +
" OR (#{Project.table_name}.lft < #{lft} AND #{Project.table_name}.rgt > #{rgt} AND #{Version.table_name}.sharing IN ('hierarchy', 'descendants'))" +
" OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt} AND #{Version.table_name}.sharing = 'hierarchy')" +
"))")
Version.
includes(:project).
where("#{Project.table_name}.id = #{id}" +
" OR (#{Project.table_name}.status <> #{Project::STATUS_ARCHIVED} AND (" +
" #{Version.table_name}.sharing = 'system'" +
" OR (#{Project.table_name}.lft >= #{r.lft} AND #{Project.table_name}.rgt <= #{r.rgt} AND #{Version.table_name}.sharing = 'tree')" +
" OR (#{Project.table_name}.lft < #{lft} AND #{Project.table_name}.rgt > #{rgt} AND #{Version.table_name}.sharing IN ('hierarchy', 'descendants'))" +
" OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt} AND #{Version.table_name}.sharing = 'hierarchy')" +
"))")
end
end
end
@@ -502,10 +513,14 @@ class Project < ActiveRecord::Base
members.select {|m| m.principal.present? && (m.mail_notification? || m.principal.mail_notification == 'all')}.collect {|m| m.principal}
end
# Returns an array of all custom fields enabled for project issues
# Returns a scope of all custom fields enabled for project issues
# (explictly associated custom fields and custom fields enabled for all projects)
def all_issue_custom_fields
@all_issue_custom_fields ||= (IssueCustomField.for_all + issue_custom_fields).uniq.sort
@all_issue_custom_fields ||= IssueCustomField.
sorted.
where("is_for_all = ? OR id IN (SELECT DISTINCT cfp.custom_field_id" +
" FROM #{table_name_prefix}custom_fields_projects#{table_name_suffix} cfp" +
" WHERE cfp.project_id = ?)", true, id)
end
# Returns an array of all custom fields enabled for project time entries
@@ -673,7 +688,7 @@ class Project < ActiveRecord::Base
# Returns an auto-generated project identifier based on the last identifier used
def self.next_identifier
p = Project.order('created_on DESC').first
p = Project.order('id DESC').first
p.nil? ? nil : p.identifier.to_s.succ
end
@@ -840,6 +855,9 @@ class Project < ActiveRecord::Base
new_issue = Issue.new
new_issue.copy_from(issue, :subtasks => false, :link => false)
new_issue.project = self
# Changing project resets the custom field values
# TODO: handle this in Issue#project=
new_issue.custom_field_values = issue.custom_field_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h}
# Reassign fixed_versions by name, since names are unique per project
if issue.fixed_version && issue.fixed_version.project == project
new_issue.fixed_version = self.versions.detect {|v| v.name == issue.fixed_version.name}
@@ -943,7 +961,7 @@ class Project < ActiveRecord::Base
def allowed_permissions
@allowed_permissions ||= begin
module_names = enabled_modules.all(:select => :name).collect {|m| m.name}
module_names = enabled_modules.loaded? ? enabled_modules.map(&:name) : enabled_modules.pluck(:name)
Redmine::AccessControl.modules_permissions(module_names).collect {|p| p.name}
end
end

View File

@@ -81,8 +81,12 @@ class QueryCustomFieldColumn < QueryColumn
end
def value(object)
cv = object.custom_values.select {|v| v.custom_field_id == @cf.id}.collect {|v| @cf.cast_value(v.value)}
cv.size > 1 ? cv.sort {|a,b| a.to_s <=> b.to_s} : cv.first
if custom_field.visible_by?(object.project, User.current)
cv = object.custom_values.select {|v| v.custom_field_id == @cf.id}.collect {|v| @cf.cast_value(v.value)}
cv.size > 1 ? cv.sort {|a,b| a.to_s <=> b.to_s} : cv.first
else
nil
end
end
def css_classes
@@ -116,17 +120,33 @@ class Query < ActiveRecord::Base
class StatementInvalid < ::ActiveRecord::StatementInvalid
end
VISIBILITY_PRIVATE = 0
VISIBILITY_ROLES = 1
VISIBILITY_PUBLIC = 2
belongs_to :project
belongs_to :user
has_and_belongs_to_many :roles, :join_table => "#{table_name_prefix}queries_roles#{table_name_suffix}", :foreign_key => "query_id"
serialize :filters
serialize :column_names
serialize :sort_criteria, Array
serialize :options, Hash
attr_protected :project_id, :user_id
validates_presence_of :name
validates_length_of :name, :maximum => 255
validates :visibility, :inclusion => { :in => [VISIBILITY_PUBLIC, VISIBILITY_ROLES, VISIBILITY_PRIVATE] }
validate :validate_query_filters
validate do |query|
errors.add(:base, l(:label_role_plural) + ' ' + l('activerecord.errors.messages.blank')) if query.visibility == VISIBILITY_ROLES && roles.blank?
end
after_save do |query|
if query.visibility_changed? && query.visibility != VISIBILITY_ROLES
query.roles.clear
end
end
class_attribute :operators
self.operators = {
@@ -245,9 +265,9 @@ class Query < ActiveRecord::Base
def editable_by?(user)
return false unless user
# Admin can edit them all and regular users can edit their private queries
return true if user.admin? || (!is_public && self.user_id == user.id)
return true if user.admin? || (is_private? && self.user_id == user.id)
# Members can not edit public queries that are for all project (only admin is allowed to)
is_public && !@is_for_all && user.allowed_to?(:manage_public_queries, project)
is_public? && !@is_for_all && user.allowed_to?(:manage_public_queries, project)
end
def trackers
@@ -429,6 +449,10 @@ class Query < ActiveRecord::Base
column_names && column_names.include?(column.is_a?(QueryColumn) ? column.name : column)
end
def has_custom_field_column?
columns.any? {|column| column.is_a? QueryCustomFieldColumn}
end
def has_default_columns?
column_names.nil? || column_names.empty?
end
@@ -545,6 +569,11 @@ class Query < ActiveRecord::Base
end
end if filters and valid?
if (c = group_by_column) && c.is_a?(QueryCustomFieldColumn)
# Excludes results for which the grouped custom field is not visible
filters_clauses << c.custom_field.visibility_by_project_condition
end
filters_clauses << project_statement
filters_clauses.reject!(&:blank?)
@@ -577,8 +606,14 @@ class Query < ActiveRecord::Base
customized_class = queried_class.reflect_on_association(assoc.to_sym).klass.base_class rescue nil
raise "Unknown #{queried_class.name} association #{assoc}" unless customized_class
end
"#{queried_table_name}.#{customized_key} #{not_in} IN (SELECT #{customized_class.table_name}.id FROM #{customized_class.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='#{customized_class}' AND #{db_table}.customized_id=#{customized_class.table_name}.id AND #{db_table}.custom_field_id=#{custom_field_id} WHERE " +
sql_for_field(field, operator, value, db_table, db_field, true) + ')'
where = sql_for_field(field, operator, value, db_table, db_field, true)
if operator =~ /[<>]/
where = "(#{where}) AND #{db_table}.#{db_field} <> ''"
end
"#{queried_table_name}.#{customized_key} #{not_in} IN (" +
"SELECT #{customized_class.table_name}.id FROM #{customized_class.table_name}" +
" LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='#{customized_class}' AND #{db_table}.customized_id=#{customized_class.table_name}.id AND #{db_table}.custom_field_id=#{custom_field_id}" +
" WHERE (#{where}) AND (#{filter[:field].visibility_by_project_condition}))"
end
# Helper method to generate the WHERE sql for a +field+, +operator+ and a +value+
@@ -727,54 +762,61 @@ class Query < ActiveRecord::Base
return sql
end
def add_custom_fields_filters(custom_fields, assoc=nil)
return unless custom_fields.present?
# Adds a filter for the given custom field
def add_custom_field_filter(field, assoc=nil)
case field.field_format
when "text"
options = { :type => :text }
when "list"
options = { :type => :list_optional, :values => field.possible_values }
when "date"
options = { :type => :date }
when "bool"
options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]] }
when "int"
options = { :type => :integer }
when "float"
options = { :type => :float }
when "user", "version"
return unless project
values = field.possible_values_options(project)
if User.current.logged? && field.field_format == 'user'
values.unshift ["<< #{l(:label_me)} >>", "me"]
end
options = { :type => :list_optional, :values => values }
else
options = { :type => :string }
end
filter_id = "cf_#{field.id}"
filter_name = field.name
if assoc.present?
filter_id = "#{assoc}.#{filter_id}"
filter_name = l("label_attribute_of_#{assoc}", :name => filter_name)
end
add_available_filter filter_id, options.merge({
:name => filter_name,
:format => field.field_format,
:field => field
})
end
custom_fields.select(&:is_filter?).sort.each do |field|
case field.field_format
when "text"
options = { :type => :text }
when "list"
options = { :type => :list_optional, :values => field.possible_values }
when "date"
options = { :type => :date }
when "bool"
options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]] }
when "int"
options = { :type => :integer }
when "float"
options = { :type => :float }
when "user", "version"
next unless project
values = field.possible_values_options(project)
if User.current.logged? && field.field_format == 'user'
values.unshift ["<< #{l(:label_me)} >>", "me"]
end
options = { :type => :list_optional, :values => values }
else
options = { :type => :string }
end
filter_id = "cf_#{field.id}"
filter_name = field.name
if assoc.present?
filter_id = "#{assoc}.#{filter_id}"
filter_name = l("label_attribute_of_#{assoc}", :name => filter_name)
end
add_available_filter filter_id, options.merge({
:name => filter_name,
:format => field.field_format,
:field => field
})
# Adds filters for the given custom fields scope
def add_custom_fields_filters(scope, assoc=nil)
scope.visible.where(:is_filter => true).sorted.each do |field|
add_custom_field_filter(field, assoc)
end
end
# Adds filters for the given associations custom fields
def add_associations_custom_fields_filters(*associations)
fields_by_class = CustomField.where(:is_filter => true).group_by(&:class)
fields_by_class = CustomField.visible.where(:is_filter => true).group_by(&:class)
associations.each do |assoc|
association_klass = queried_class.reflect_on_association(assoc).klass
fields_by_class.each do |field_class, fields|
if field_class.customized_class <= association_klass
add_custom_fields_filters(fields, assoc)
fields.sort.each do |field|
add_custom_field_filter(field, assoc)
end
end
end
end

View File

@@ -249,19 +249,18 @@ class Repository < ActiveRecord::Base
# Default behaviour is to search in cached changesets
def latest_changesets(path, rev, limit=10)
if path.blank?
changesets.find(
:all,
:include => :user,
:order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
:limit => limit)
changesets.
reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
limit(limit).
preload(:user).
all
else
filechanges.find(
:all,
:include => {:changeset => :user},
:conditions => ["path = ?", path.with_leading_slash],
:order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
:limit => limit
).collect(&:changeset)
filechanges.
where("path = ?", path.with_leading_slash).
reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
limit(limit).
preload(:changeset => :user).
collect(&:changeset)
end
end
@@ -393,7 +392,7 @@ class Repository < ActiveRecord::Base
end
def set_as_default?
new_record? && project && !Repository.first(:conditions => {:project_id => project.id})
new_record? && project && Repository.where(:project_id => project.id).empty?
end
protected

View File

@@ -68,15 +68,11 @@ class Repository::Bazaar < Repository
full_path = File.join(root_url, e.path)
e.size = File.stat(full_path).size if File.file?(full_path)
end
c = Change.find(
:first,
:include => :changeset,
:conditions => [
"#{Change.table_name}.revision = ? and #{Changeset.table_name}.repository_id = ?",
e.lastrev.revision,
id
],
:order => "#{Changeset.table_name}.revision DESC")
c = Change.
includes(:changeset).
where("#{Change.table_name}.revision = ? and #{Changeset.table_name}.repository_id = ?", e.lastrev.revision, id).
order("#{Changeset.table_name}.revision DESC").
first
if c
e.lastrev.identifier = c.changeset.revision
e.lastrev.name = c.changeset.revision

View File

@@ -143,14 +143,11 @@ class Repository::Cvs < Repository
)
cmt = Changeset.normalize_comments(revision.message, repo_log_encoding)
author_utf8 = Changeset.to_utf8(revision.author, repo_log_encoding)
cs = changesets.find(
:first,
:conditions => {
:committed_on => tmp_time - time_delta .. tmp_time + time_delta,
:committer => author_utf8,
:comments => cmt
}
)
cs = changesets.where(
:committed_on => tmp_time - time_delta .. tmp_time + time_delta,
:committer => author_utf8,
:comments => cmt
).first
# create a new changeset....
unless cs
# we use a temporaray revision number here (just for inserting)
@@ -185,10 +182,10 @@ class Repository::Cvs < Repository
end
# Renumber new changesets in chronological order
Changeset.all(
:order => 'committed_on ASC, id ASC',
:conditions => ["repository_id = ? AND revision LIKE 'tmp%'", id]
).each do |changeset|
Changeset.
order('committed_on ASC, id ASC').
where("repository_id = ? AND revision LIKE 'tmp%'", id).
each do |changeset|
changeset.update_attribute :revision, next_revision_number
end
end # transaction

View File

@@ -191,13 +191,8 @@ class Repository::Git < Repository
offset = 0
revisions_copy = revisions.clone # revisions will change
while offset < revisions_copy.size
recent_changesets_slice = changesets.find(
:all,
:conditions => [
'scmid IN (?)',
revisions_copy.slice(offset, limit).map{|x| x.scmid}
]
)
scmids = revisions_copy.slice(offset, limit).map{|x| x.scmid}
recent_changesets_slice = changesets.where(:scmid => scmids).all
# Subtract revisions that redmine already knows about
recent_revisions = recent_changesets_slice.map{|c| c.scmid}
revisions.reject!{|r| recent_revisions.include?(r.scmid)}
@@ -246,13 +241,7 @@ class Repository::Git < Repository
revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
return [] if revisions.nil? || revisions.empty?
changesets.find(
:all,
:conditions => [
"scmid IN (?)",
revisions.map!{|c| c.scmid}
]
)
changesets.where(:scmid => revisions.map {|c| c.scmid}).all
end
def clear_extra_info_of_changesets

View File

@@ -20,7 +20,7 @@ require 'redmine/scm/adapters/subversion_adapter'
class Repository::Subversion < Repository
attr_protected :root_url
validates_presence_of :url
validates_format_of :url, :with => /\A(http|https|svn(\+[^\s:\/\\]+)?|file):\/\/.+/i
validates_format_of :url, :with => %r{\A(http|https|svn(\+[^\s:\/\\]+)?|file):\/\/.+}i
def self.scm_adapter_class
Redmine::Scm::Adapters::SubversionAdapter

View File

@@ -52,6 +52,7 @@ class Role < ActiveRecord::Base
WorkflowRule.copy(nil, source_role, nil, proxy_association.owner)
end
end
has_and_belongs_to_many :custom_fields, :join_table => "#{table_name_prefix}custom_fields_roles#{table_name_suffix}", :foreign_key => "role_id"
has_many :member_roles, :dependent => :destroy
has_many :members, :through => :member_roles
@@ -137,7 +138,7 @@ class Role < ActiveRecord::Base
def anonymous?
builtin == 2
end
# Return true if the role is a project member role
def member?
!self.builtin?

View File

@@ -132,15 +132,87 @@ class Setting < ActiveRecord::Base
def self.#{name}=(value)
self[:#{name}] = value
end
END_SRC
END_SRC
class_eval src, __FILE__, __LINE__
end
# Sets a setting value from params
def self.set_from_params(name, params)
params = params.dup
params.delete_if {|v| v.blank? } if params.is_a?(Array)
m = "#{name}_from_params"
if respond_to? m
self[name.to_sym] = send m, params
else
self[name.to_sym] = params
end
end
# Returns a hash suitable for commit_update_keywords setting
#
# Example:
# params = {:keywords => ['fixes', 'closes'], :status_id => ["3", "5"], :done_ratio => ["", "100"]}
# Setting.commit_update_keywords_from_params(params)
# # => [{'keywords => 'fixes', 'status_id' => "3"}, {'keywords => 'closes', 'status_id' => "5", 'done_ratio' => "100"}]
def self.commit_update_keywords_from_params(params)
s = []
if params.is_a?(Hash) && params.key?(:keywords) && params.values.all? {|v| v.is_a? Array}
attributes = params.except(:keywords).keys
params[:keywords].each_with_index do |keywords, i|
next if keywords.blank?
s << attributes.inject({}) {|h, a|
value = params[a][i].to_s
h[a.to_s] = value if value.present?
h
}.merge('keywords' => keywords)
end
end
s
end
# Helper that returns an array based on per_page_options setting
def self.per_page_options_array
per_page_options.split(%r{[\s,]}).collect(&:to_i).select {|n| n > 0}.sort
end
# Helper that returns a Hash with single update keywords as keys
def self.commit_update_keywords_array
a = []
if commit_update_keywords.is_a?(Array)
commit_update_keywords.each do |rule|
next unless rule.is_a?(Hash)
rule = rule.dup
rule.delete_if {|k, v| v.blank?}
keywords = rule['keywords'].to_s.downcase.split(",").map(&:strip).reject(&:blank?)
next if keywords.empty?
a << rule.merge('keywords' => keywords)
end
end
a
end
def self.commit_fix_keywords
ActiveSupport::Deprecation.warn "Setting.commit_fix_keywords is deprecated and will be removed in Redmine 3"
if commit_update_keywords.is_a?(Array)
commit_update_keywords.first && commit_update_keywords.first['keywords']
end
end
def self.commit_fix_status_id
ActiveSupport::Deprecation.warn "Setting.commit_fix_status_id is deprecated and will be removed in Redmine 3"
if commit_update_keywords.is_a?(Array)
commit_update_keywords.first && commit_update_keywords.first['status_id']
end
end
def self.commit_fix_done_ratio
ActiveSupport::Deprecation.warn "Setting.commit_fix_done_ratio is deprecated and will be removed in Redmine 3"
if commit_update_keywords.is_a?(Array)
commit_update_keywords.first && commit_update_keywords.first['done_ratio']
end
end
def self.openid?
Object.const_defined?(:OpenID) && self[:openid].to_i > 0
end
@@ -154,7 +226,7 @@ class Setting < ActiveRecord::Base
clear_cache
end
end
# Clears the settings cache
def self.clear_cache
@cached_settings.clear

View File

@@ -24,11 +24,15 @@ class TimeEntryActivity < Enumeration
OptionName
end
def objects
TimeEntry.where(:activity_id => self_and_descendants(1).map(&:id))
end
def objects_count
time_entries.count
objects.count
end
def transfer_relations(to)
time_entries.update_all("activity_id = #{to.id}")
objects.update_all(:activity_id => to.id)
end
end

View File

@@ -84,15 +84,15 @@ class TimeEntryQuery < Query
add_available_filter "comments", :type => :text
add_available_filter "hours", :type => :float
add_custom_fields_filters(TimeEntryCustomField.where(:is_filter => true).all)
add_custom_fields_filters(TimeEntryCustomField)
add_associations_custom_fields_filters :project, :issue, :user
end
def available_columns
return @available_columns if @available_columns
@available_columns = self.class.available_columns.dup
@available_columns += TimeEntryCustomField.all.map {|cf| QueryCustomFieldColumn.new(cf) }
@available_columns += IssueCustomField.all.map {|cf| QueryAssociationCustomFieldColumn.new(:issue, cf) }
@available_columns += TimeEntryCustomField.visible.all.map {|cf| QueryCustomFieldColumn.new(cf) }
@available_columns += IssueCustomField.visible.all.map {|cf| QueryAssociationCustomFieldColumn.new(:issue, cf) }
@available_columns
end
@@ -100,6 +100,15 @@ class TimeEntryQuery < Query
@default_columns_names ||= [:project, :spent_on, :user, :activity, :issue, :comments, :hours]
end
def results_scope(options={})
order_option = [group_by_sort_order, options[:order]].flatten.reject(&:blank?)
TimeEntry.visible.
where(statement).
order(order_option).
joins(joins_for_order_statement(order_option.join(',')))
end
# Accepts :from/:to params as shortcut filters
def build_from_params(params)
super

View File

@@ -81,7 +81,7 @@ class User < Principal
acts_as_customizable
attr_accessor :password, :password_confirmation
attr_accessor :password, :password_confirmation, :generate_password
attr_accessor :last_before_login_on
# Prevents unauthorized assignments
attr_protected :login, :admin, :password, :password_confirmation, :hashed_password
@@ -103,8 +103,9 @@ class User < Principal
validate :validate_password_length
before_create :set_mail_notification
before_save :update_hashed_password
before_save :generate_password_if_needed, :update_hashed_password
before_destroy :remove_references_before_destroy
after_save :update_notified_project_ids
scope :in_group, lambda {|group|
group_id = group.is_a?(Group) ? group.id : group.to_i
@@ -133,6 +134,9 @@ class User < Principal
@name = nil
@projects_by_role = nil
@membership_by_project_id = nil
@notified_projects_ids = nil
@notified_projects_ids_changed = false
@builtin_role = nil
base_reload(*args)
end
@@ -154,7 +158,7 @@ class User < Principal
end
# Returns the user that matches provided login and password, or nil
def self.try_to_login(login, password)
def self.try_to_login(login, password, active_only=true)
login = login.to_s
password = password.to_s
@@ -163,8 +167,8 @@ class User < Principal
user = find_by_login(login)
if user
# user is already in local database
return nil unless user.active?
return nil unless user.check_password?(password)
return nil if !user.active? && active_only
else
# user is not yet registered, try to authenticate with available sources
attrs = AuthSource.authenticate(login, password)
@@ -178,7 +182,7 @@ class User < Principal
end
end
end
user.update_column(:last_login_on, Time.now) if user && !user.new_record?
user.update_column(:last_login_on, Time.now) if user && !user.new_record? && user.active?
user
rescue => text
raise text
@@ -276,13 +280,20 @@ class User < Principal
return auth_source.allow_password_changes?
end
# Generate and set a random password. Useful for automated user creation
# Based on Token#generate_token_value
#
def random_password
def must_change_password?
must_change_passwd? && change_password_allowed?
end
def generate_password?
generate_password == '1' || generate_password == true
end
# Generate and set a random password on given length
def random_password(length=40)
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
chars -= %w(0 O 1 l)
password = ''
40.times { |i| password << chars[rand(chars.size-1)] }
length.times {|i| password << chars[SecureRandom.random_number(chars.size)] }
self.password = password
self.password_confirmation = password
self
@@ -322,12 +333,20 @@ class User < Principal
end
def notified_project_ids=(ids)
Member.update_all("mail_notification = #{connection.quoted_false}", ['user_id = ?', id])
Member.update_all("mail_notification = #{connection.quoted_true}", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty?
@notified_projects_ids = nil
notified_projects_ids
@notified_projects_ids_changed = true
@notified_projects_ids = ids
end
# Updates per project notifications (after_save callback)
def update_notified_project_ids
if @notified_projects_ids_changed
ids = (mail_notification == 'selected' ? Array.wrap(notified_projects_ids).reject(&:blank?) : [])
members.update_all(:mail_notification => false)
members.where(:project_id => ids).update_all(:mail_notification => true) if ids.any?
end
end
private :update_notified_project_ids
def valid_notification_options
self.class.valid_notification_options(self)
end
@@ -428,23 +447,20 @@ class User < Principal
@membership_by_project_id[project_id]
end
# Returns the user's bult-in role
def builtin_role
@builtin_role ||= Role.non_member
end
# Return user's roles for project
def roles_for_project(project)
roles = []
# No role on archived projects
return roles if project.nil? || project.archived?
if logged?
# Find project membership
membership = membership(project)
if membership
roles = membership.roles
else
@role_non_member ||= Role.non_member
roles << @role_non_member
end
if membership = membership(project)
roles = membership.roles
else
@role_anonymous ||= Role.anonymous
roles << @role_anonymous
roles << builtin_role
end
roles
end
@@ -536,7 +552,7 @@ class User < Principal
allowed_to?(action, nil, options.reverse_merge(:global => true), &block)
end
# Returns true if the user is allowed to delete his own account
# Returns true if the user is allowed to delete the user's own account
def own_account_deletable?
Setting.unsubscribe? &&
(!admin? || User.active.where("admin = ? AND id <> ?", true, id).exists?)
@@ -547,6 +563,7 @@ class User < Principal
'lastname',
'mail',
'mail_notification',
'notified_project_ids',
'language',
'custom_field_values',
'custom_fields',
@@ -554,6 +571,8 @@ class User < Principal
safe_attributes 'status',
'auth_source_id',
'generate_password',
'must_change_passwd',
:if => lambda {|user, current_user| current_user.admin?}
safe_attributes 'group_ids',
@@ -623,6 +642,7 @@ class User < Principal
protected
def validate_password_length
return if password.blank? && generate_password?
# Password length validation based on setting
if !password.nil? && password.size < Setting.password_min_length.to_i
errors.add(:password, :too_short, :count => Setting.password_min_length.to_i)
@@ -631,6 +651,13 @@ class User < Principal
private
def generate_password_if_needed
if generate_password? && auth_source.nil?
length = [Setting.password_min_length.to_i + 2, 10].max
random_password(length)
end
end
# Removes references that are not handled by associations
# Things that are not deleted are reassociated with the anonymous user
def remove_references_before_destroy
@@ -647,7 +674,7 @@ class User < Principal
Message.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
News.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
# Remove private queries and keep public ones
::Query.delete_all ['user_id = ? AND is_public = ?', id, false]
::Query.delete_all ['user_id = ? AND visibility = ?', id, ::Query::VISIBILITY_PRIVATE]
::Query.update_all ['user_id = ?', substitute.id], ['user_id = ?', id]
TimeEntry.update_all ['user_id = ?', substitute.id], ['user_id = ?', id]
Token.delete_all ['user_id = ?', id]
@@ -692,7 +719,16 @@ class AnonymousUser < User
UserPreference.new(:user => self)
end
def member_of?(project)
# Returns the user's bult-in role
def builtin_role
@builtin_role ||= Role.anonymous
end
def membership(*args)
nil
end
def member_of?(*args)
false
end

View File

@@ -22,7 +22,7 @@ class UserPreference < ActiveRecord::Base
attr_protected :others, :user_id
before_save :set_others_hash
def initialize(attributes=nil, *args)
super
self.others ||= {}
@@ -33,7 +33,7 @@ class UserPreference < ActiveRecord::Base
end
def [](attr_name)
if attribute_present? attr_name
if has_attribute? attr_name
super
else
others ? others[attr_name] : nil
@@ -41,7 +41,7 @@ class UserPreference < ActiveRecord::Base
end
def []=(attr_name, value)
if attribute_present? attr_name
if has_attribute? attr_name
super
else
h = (read_attribute(:others) || {}).dup
@@ -56,4 +56,7 @@ class UserPreference < ActiveRecord::Base
def warn_on_leaving_unsaved; self[:warn_on_leaving_unsaved] || '1'; end
def warn_on_leaving_unsaved=(value); self[:warn_on_leaving_unsaved]=value; end
def no_self_notified; (self[:no_self_notified] == true || self[:no_self_notified] == '1'); end
def no_self_notified=(value); self[:no_self_notified]=value; end
end

View File

@@ -40,14 +40,15 @@ class Version < ActiveRecord::Base
includes(:project).where(Project.allowed_to_condition(args.first || User.current, :view_issues))
}
safe_attributes 'name',
safe_attributes 'name',
'description',
'effective_date',
'due_date',
'wiki_page_title',
'status',
'sharing',
'custom_field_values'
'custom_field_values',
'custom_fields'
# Returns true if +user+ or current user is allowed to view the version
def visible?(user=User.current)

View File

@@ -23,6 +23,19 @@ class Watcher < ActiveRecord::Base
validates_uniqueness_of :user_id, :scope => [:watchable_type, :watchable_id]
validate :validate_user
# Returns true if at least one object among objects is watched by user
def self.any_watched?(objects, user)
objects = objects.reject(&:new_record?)
if objects.any?
objects.group_by {|object| object.class.base_class}.each do |base_class, objects|
if Watcher.where(:watchable_type => base_class.name, :watchable_id => objects.map(&:id), :user_id => user.id).exists?
return true
end
end
end
false
end
# Unwatch things that users are no longer allowed to view
def self.prune(options={})
if options.has_key?(:user)

View File

@@ -50,10 +50,10 @@ class Wiki < ActiveRecord::Base
@page_found_with_redirect = false
title = start_page if title.blank?
title = Wiki.titleize(title)
page = pages.first(:conditions => ["LOWER(title) = LOWER(?)", title])
page = pages.where("LOWER(title) = LOWER(?)", title).first
if !page && !(options[:with_redirect] == false)
# search for a redirect
redirect = redirects.first(:conditions => ["LOWER(title) = LOWER(?)", title])
redirect = redirects.where("LOWER(title) = LOWER(?)", title).first
if redirect
page = find_page(redirect.redirects_to, :with_redirect => false)
@page_found_with_redirect = true

View File

@@ -26,6 +26,8 @@ class WikiContent < ActiveRecord::Base
acts_as_versioned
after_save :send_notification
def visible?(user=User.current)
page.visible?(user)
end
@@ -145,4 +147,19 @@ class WikiContent < ActiveRecord::Base
end
end
end
private
def send_notification
# new_record? returns false in after_save callbacks
if id_changed?
if Setting.notified_events.include?('wiki_content_added')
Mailer.wiki_content_added(self).deliver
end
elsif text_changed?
if Setting.notified_events.include?('wiki_content_updated')
Mailer.wiki_content_updated(self).deliver
end
end
end
end

View File

@@ -175,9 +175,10 @@ class WikiPage < ActiveRecord::Base
end
# Saves the page and its content if text was changed
def save_with_content
def save_with_content(content)
ret = nil
transaction do
self.content = content
if new_record?
# Rails automatically saves associated content
ret = save

View File

@@ -43,11 +43,17 @@
<% content_for :sidebar do %>
<%= form_tag({}, :method => :get) do %>
<h3><%= l(:label_activity) %></h3>
<p><% @activity.event_types.each do |t| %>
<%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %>
<label for="show_<%=t%>"><%= link_to(l("label_#{t.singularize}_plural"), {"show_#{t}" => 1, :user_id => params[:user_id], :from => params[:from]})%></label>
<br />
<% end %></p>
<ul>
<% @activity.event_types.each do |t| %>
<li>
<%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %>
<label for="show_<%=t%>">
<%= link_to(l("label_#{t.singularize}_plural"),
{"show_#{t}" => 1, :user_id => params[:user_id], :from => params[:from]})%>
</label>
</li>
<% end %>
</ul>
<% if @project && @project.descendants.active.any? %>
<%= hidden_field_tag 'with_subprojects', 0 %>
<p><label><%= check_box_tag 'with_subprojects', 1, @with_subprojects %> <%=l(:label_subproject_plural)%></label></p>

View File

@@ -1,4 +1,4 @@
<h2><%= l(:label_plugins) %></h2>
<%= title l(:label_plugins) %>
<% if @plugins.any? %>
<table class="list plugins">

View File

@@ -2,7 +2,7 @@
<%= link_to l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add' %>
</div>
<h2><%=l(:label_project_plural)%></h2>
<%= title l(:label_project_plural) %>
<%= form_tag({}, :method => :get) do %>
<fieldset><legend><%= l(:label_filter_plural) %></legend>
@@ -41,5 +41,3 @@
</tbody>
</table>
</div>
<% html_title(l(:label_project_plural)) -%>

View File

@@ -1,4 +1,8 @@
var fileSpan = $('#attachments_<%= j params[:attachment_id] %>');
<% if @attachment.new_record? %>
fileSpan.hide();
alert("<%= escape_javascript @attachment.errors.full_messages.join(', ') %>");
<% else %>
$('<input>', { type: 'hidden', name: 'attachments[<%= j params[:attachment_id] %>][token]' } ).val('<%= j @attachment.token %>').appendTo(fileSpan);
fileSpan.find('a.remove-upload')
.attr({
@@ -7,3 +11,4 @@ fileSpan.find('a.remove-upload')
href: '<%= j attachment_path(@attachment, :attachment_id => params[:attachment_id], :format => 'js') %>'
})
.off('click');
<% end %>

View File

@@ -1,4 +1,4 @@
<h2><%=l(:label_auth_source)%> (<%= h(@auth_source.auth_method_name) %>)</h2>
<%= title [l(:label_auth_source_plural), auth_sources_path], @auth_source.name %>
<%= labelled_form_for @auth_source, :as => :auth_source, :url => auth_source_path(@auth_source), :html => {:id => 'auth_source_form'} do |f| %>
<%= render :partial => auth_source_partial_name(@auth_source), :locals => { :f => f } %>

View File

@@ -2,7 +2,7 @@
<%= link_to l(:label_auth_source_new), {:action => 'new'}, :class => 'icon icon-add' %>
</div>
<h2><%=l(:label_auth_source_plural)%></h2>
<%= title l(:label_auth_source_plural) %>
<table class="list">
<thead><tr>

View File

@@ -1,4 +1,4 @@
<h2><%=l(:label_auth_source_new)%> (<%= h(@auth_source.auth_method_name) %>)</h2>
<%= title [l(:label_auth_source_plural), auth_sources_path], "#{l(:label_auth_source_new)} (#{@auth_source.auth_method_name})" %>
<%= labelled_form_for @auth_source, :as => :auth_source, :url => auth_sources_path, :html => {:id => 'auth_source_form'} do |f| %>
<%= hidden_field_tag 'type', @auth_source.type %>

View File

@@ -3,8 +3,8 @@
<tbody>
<% line_num = 1 %>
<% syntax_highlight_lines(filename, Redmine::CodesetUtil.to_utf8_by_setting(content)).each do |line| %>
<tr>
<th class="line-num" id="L<%= line_num %>">
<tr id="L<%= line_num %>">
<th class="line-num">
<a href="#L<%= line_num %>"><%= line_num %></a>
</th>
<td class="line-code">

View File

@@ -6,7 +6,7 @@
<li><%= link_to l(tab[:label]), { :tab => tab[:name] },
:id => "tab-#{tab[:name]}",
:class => (tab[:name] != selected_tab ? nil : 'selected'),
:onclick => "showTab('#{tab[:name]}'); this.blur(); return false;" %></li>
:onclick => "showTab('#{tab[:name]}', this.href); this.blur(); return false;" %></li>
<% end -%>
</ul>
<div class="tabs-buttons" style="display:none;">

View File

@@ -131,7 +131,7 @@
<% else %>
<li><%= context_menu_link l(:button_copy), bulk_edit_issues_path(:ids => @issue_ids, :copy => '1'),
:class => 'icon-copy', :disabled => !@can[:move] %></li>
<% end %>
<% end %>
<li><%= context_menu_link l(:button_delete), issues_path(:ids => @issue_ids, :back_url => @back),
:method => :delete, :data => {:confirm => issues_destroy_confirmation_message(@issues)}, :class => 'icon-del', :disabled => !@can[:delete] %></li>

View File

@@ -1,5 +1,9 @@
<%= error_messages_for 'custom_field' %>
<% if @custom_field.is_a?(IssueCustomField) %>
<div class="splitcontentleft">
<% end %>
<div class="box tabular">
<p><%= f.text_field :name, :required => true %></p>
<p><%= f.select :field_format, custom_field_formats_for_select(@custom_field), {}, :disabled => !@custom_field.new_record? %></p>
@@ -46,24 +50,28 @@
<div class="box tabular">
<% case @custom_field.class.name
when "IssueCustomField" %>
<fieldset><legend><%=l(:label_tracker_plural)%></legend>
<% Tracker.sorted.all.each do |tracker| %>
<%= check_box_tag "custom_field[tracker_ids][]",
tracker.id,
(@custom_field.trackers.include? tracker),
:id => "custom_field_tracker_ids_#{tracker.id}" %>
<label class="no-css" for="custom_field_tracker_ids_<%=tracker.id%>">
<%= h(tracker.name) %>
</label>
<% end %>
<%= hidden_field_tag "custom_field[tracker_ids][]", '' %>
</fieldset>
&nbsp;
<p><%= f.check_box :is_required %></p>
<p><%= f.check_box :is_for_all %></p>
<p><%= f.check_box :is_filter %></p>
<p><%= f.check_box :searchable %></p>
<p>
<label><%= l(:field_visible) %></label>
<label class="block">
<%= radio_button_tag 'custom_field[visible]', 1, @custom_field.visible?, :id => 'custom_field_visible_on' %>
<%= l(:label_visibility_public) %>
</label>
<label class="block">
<%= radio_button_tag 'custom_field[visible]', 0, !@custom_field.visible?, :id => 'custom_field_visible_off' %>
<%= l(:label_visibility_roles) %>:
</label>
<% Role.givable.sorted.each do |role| %>
<label class="block custom_field_role" style="padding-left:2em;">
<%= check_box_tag 'custom_field[role_ids][]', role.id, @custom_field.roles.include?(role) %>
<%= role.name %>
</label>
<% end %>
<%= hidden_field_tag 'custom_field[role_ids][]', '' %>
</p>
<% when "UserCustomField" %>
<p><%= f.check_box :is_required %></p>
@@ -95,5 +103,45 @@ when "IssueCustomField" %>
<% end %>
<%= call_hook(:"view_custom_fields_form_#{@custom_field.type.to_s.underscore}", :custom_field => @custom_field, :form => f) %>
</div>
<%= submit_tag l(:button_save) %>
<% if @custom_field.is_a?(IssueCustomField) %>
</div>
<div class="splitcontentright">
<fieldset class="box"><legend><%=l(:label_tracker_plural)%></legend>
<% Tracker.sorted.all.each do |tracker| %>
<%= check_box_tag "custom_field[tracker_ids][]",
tracker.id,
(@custom_field.trackers.include? tracker),
:id => "custom_field_tracker_ids_#{tracker.id}" %>
<label class="no-css" for="custom_field_tracker_ids_<%=tracker.id%>">
<%= h(tracker.name) %>
</label>
<% end %>
<%= hidden_field_tag "custom_field[tracker_ids][]", '' %>
</fieldset>
<fieldset class="box" id="custom_field_project_ids"><legend><%= l(:label_project_plural) %></legend>
<%= render_project_nested_lists(Project.all) do |p|
content_tag('label', check_box_tag('custom_field[project_ids][]', p.id, @custom_field.projects.to_a.include?(p), :id => nil) + ' ' + h(p))
end %>
<%= hidden_field_tag('custom_field[project_ids][]', '', :id => nil) %>
<p><%= check_all_links 'custom_field_project_ids' %></p>
</fieldset>
</div>
<% end %>
<% include_calendar_headers_tags %>
<%= javascript_tag do %>
function toggleCustomFieldRoles(){
var checked = $("#custom_field_visible_on").is(':checked');
$('.custom_field_role input').attr('disabled', checked);
}
$("#custom_field_visible_on, #custom_field_visible_off").change(toggleCustomFieldRoles);
$(document).ready(toggleCustomFieldRoles);
$("#custom_field_is_for_all").change(function(){
$("#custom_field_project_ids input").attr("disabled", $(this).is(":checked"));
}).trigger('change');
<% end %>

View File

@@ -1,8 +1,7 @@
<h2><%= link_to l(:label_custom_field_plural), :controller => 'custom_fields', :action => 'index' %>
&#187; <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %>
&#187; <%=h @custom_field.name %></h2>
<%= title [l(:label_custom_field_plural), custom_fields_path],
[l(@custom_field.type_name), custom_fields_path(:tab => @custom_field.class.name)],
@custom_field.name %>
<%= labelled_form_for :custom_field, @custom_field, :url => custom_field_path(@custom_field), :html => {:method => :put, :id => 'custom_field_form'} do |f| %>
<%= render :partial => 'form', :locals => { :f => f } %>
<%= submit_tag l(:button_save) %>
<% end %>

View File

@@ -0,0 +1,42 @@
api.array :custom_fields do
@custom_fields.each do |field|
api.custom_field do
api.id field.id
api.name field.name
api.customized_type field.class.customized_class.name.underscore if field.class.customized_class
api.field_format field.field_format
api.regexp field.regexp
api.min_length (field.min_length == 0 ? nil : field.min_length)
api.max_length (field.max_length == 0 ? nil : field.max_length)
api.is_required field.is_required?
api.is_filter field.is_filter?
api.searchable field.searchable
api.multiple field.multiple?
api.default_value field.default_value
api.visible field.visible?
if field.field_format == 'list'
api.array :possible_values do
field.possible_values.each do |v|
api.possible_value do
api.value v
end
end
end
end
if field.is_a?(IssueCustomField)
api.trackers do
field.trackers.each do |tracker|
api.tracker :id => tracker.id, :name => tracker.name
end
end
api.roles do
field.roles.each do |role|
api.role :id => role.id, :name => role.name
end
end
end
end
end
end

View File

@@ -1,5 +1,3 @@
<h2><%=l(:label_custom_field_plural)%></h2>
<%= title l(:label_custom_field_plural) %>
<%= render_tabs custom_fields_tabs %>
<% html_title(l(:label_custom_field_plural)) -%>

View File

@@ -1,11 +1,10 @@
<h2><%= link_to l(:label_custom_field_plural), :controller => 'custom_fields', :action => 'index' %>
&#187; <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %>
&#187; <%= l(:label_custom_field_new) %></h2>
<%= title [l(:label_custom_field_plural), custom_fields_path],
[l(@custom_field.type_name), custom_fields_path(:tab => @custom_field.class.name)],
l(:label_custom_field_new) %>
<%= labelled_form_for :custom_field, @custom_field, :url => custom_fields_path, :html => {:id => 'custom_field_form'} do |f| %>
<%= render :partial => 'form', :locals => { :f => f } %>
<%= hidden_field_tag 'type', @custom_field.type %>
<%= submit_tag l(:button_save) %>
<% end %>
<%= javascript_tag do %>

View File

@@ -8,7 +8,7 @@
<%= labelled_form_for @document, :url => project_documents_path(@project), :html => {:multipart => true} do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>
<p>
<%= submit_tag l(:button_create) %>
<%= submit_tag l(:button_create) %>
<%= link_to l(:button_cancel), "#", :onclick => '$("#add-document").hide(); return false;' %>
</p>
<% end %>
@@ -25,10 +25,16 @@
<% content_for :sidebar do %>
<h3><%= l(:label_sort_by, '') %></h3>
<%= link_to l(:field_category), {:sort_by => 'category'}, :class => (@sort_by == 'category' ? 'selected' :nil) %><br />
<%= link_to l(:label_date), {:sort_by => 'date'}, :class => (@sort_by == 'date' ? 'selected' :nil) %><br />
<%= link_to l(:field_title), {:sort_by => 'title'}, :class => (@sort_by == 'title' ? 'selected' :nil) %><br />
<%= link_to l(:field_author), {:sort_by => 'author'}, :class => (@sort_by == 'author' ? 'selected' :nil) %>
<ul>
<li><%= link_to(l(:field_category), {:sort_by => 'category'},
:class => (@sort_by == 'category' ? 'selected' :nil)) %></li>
<li><%= link_to(l(:label_date), {:sort_by => 'date'},
:class => (@sort_by == 'date' ? 'selected' :nil)) %></li>
<li><%= link_to(l(:field_title), {:sort_by => 'title'},
:class => (@sort_by == 'title' ? 'selected' :nil)) %></li>
<li><%= link_to(l(:field_author), {:sort_by => 'author'},
:class => (@sort_by == 'author' ? 'selected' :nil)) %></li>
</ul>
<% end %>
<% html_title(l(:label_document_plural)) -%>

View File

@@ -12,7 +12,7 @@
<p><em><%=h @document.category.name %><br />
<%= format_date @document.created_on %></em></p>
<div class="wiki">
<%= textilizable @document.description, :attachments => @document.attachments %>
<%= textilizable @document, :description, :attachments => @document.attachments %>
</div>
<h3><%= l(:label_attachment_plural) %></h3>

View File

@@ -1,10 +1,10 @@
<h2><%= l(@enumeration.option_name) %>: <%=h @enumeration %></h2>
<%= title [l(@enumeration.option_name), enumerations_path], @enumeration.name %>
<%= form_tag({}, :method => :delete) do %>
<div class="box">
<p><strong><%= l(:text_enumeration_destroy_question, @enumeration.objects_count) %></strong></p>
<p><label for='reassign_to_id'><%= l(:text_enumeration_category_reassign_to) %></label>
<%= select_tag 'reassign_to_id', (content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") + options_from_collection_for_select(@enumerations, 'id', 'name')) %></p>
<%= select_tag 'reassign_to_id', (content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---", :value => '') + options_from_collection_for_select(@enumerations, 'id', 'name')) %></p>
</div>
<%= submit_tag l(:button_apply) %>

View File

@@ -1,4 +1,4 @@
<h2><%= link_to l(@enumeration.option_name), enumerations_path %> &#187; <%=h @enumeration %></h2>
<%= title [l(@enumeration.option_name), enumerations_path], @enumeration.name %>
<%= labelled_form_for :enumeration, @enumeration, :url => enumeration_path(@enumeration), :html => {:method => :put} do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>

View File

@@ -10,7 +10,7 @@
<th><%= l(:field_name) %></th>
<th style="width:15%;"><%= l(:field_is_default) %></th>
<th style="width:15%;"><%= l(:field_active) %></th>
<th style="width:15%;"></th>
<th style="width:15%;"><%=l(:button_sort)%></th>
<th align="center" style="width:10%;"> </th>
</tr></thead>
<% enumerations.each do |enumeration| %>
@@ -18,7 +18,7 @@
<td><%= link_to h(enumeration), edit_enumeration_path(enumeration) %></td>
<td class="center" style="width:15%;"><%= checked_image enumeration.is_default? %></td>
<td class="center" style="width:15%;"><%= checked_image enumeration.active? %></td>
<td style="width:15%;"><%= reorder_links('enumeration', {:action => 'update', :id => enumeration}, :put) %></td>
<td align="center" style="width:15%;"><%= reorder_links('enumeration', {:action => 'update', :id => enumeration}, :put) %></td>
<td class="buttons">
<%= delete_link enumeration_path(enumeration) %>
</td>

View File

@@ -1,4 +1,4 @@
<h2><%= link_to l(@enumeration.option_name), enumerations_path %> &#187; <%=l(:label_enumeration_new)%></h2>
<%= title [l(@enumeration.option_name), enumerations_path], l(:label_enumeration_new) %>
<%= labelled_form_for :enumeration, @enumeration, :url => enumerations_path do |f| %>
<%= f.hidden_field :type %>

View File

@@ -1,4 +1,11 @@
<% @gantt.view = self %>
<div class="contextual">
<% if !@query.new_record? && @query.editable_by?(User.current) %>
<%= link_to l(:button_edit), edit_query_path(@query, :gantt => 1), :class => 'icon icon-edit' %>
<%= delete_link query_path(@query, :gantt => 1) %>
<% end %>
</div>
<h2><%= @query.new_record? ? l(:label_gantt) : h(@query.name) %></h2>
<%= form_tag({:controller => 'gantts', :action => 'show',
@@ -6,6 +13,7 @@
:year => params[:year], :months => params[:months]},
:method => :get, :id => 'query_form') do %>
<%= hidden_field_tag 'set_filter', '1' %>
<%= hidden_field_tag 'gantt', '1' %>
<fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>">
<legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
<div style="<%= @query.new_record? ? "" : "display: none;" %>">
@@ -20,8 +28,8 @@
<td>
<fieldset>
<legend><%= l(:label_related_issues) %></legend>
<label>
<%= check_box_tag "draw_rels", params["draw_rels"], params[:set_filter].blank? || params[:draw_rels] %>
<label for="draw_relations">
<%= check_box 'query', 'draw_relations', :id => 'draw_relations' %>
<% rels = [IssueRelation::TYPE_BLOCKS, IssueRelation::TYPE_PRECEDES] %>
<% rels.each do |rel| %>
<% color = Redmine::Helpers::Gantt::DRAW_TYPES[rel][:color] %>
@@ -35,8 +43,8 @@
<td>
<fieldset>
<legend><%= l(:label_gantt_progress_line) %></legend>
<label>
<%= check_box_tag "draw_progress_line", params[:draw_progress_line], params[:draw_progress_line] %>
<label for="draw_progress_line">
<%= check_box 'query', 'draw_progress_line', :id => 'draw_progress_line' %>
<%= l(:label_display) %>
</label>
</fieldset>
@@ -62,6 +70,11 @@
:class => 'icon icon-checked' %>
<%= link_to l(:button_clear), { :project_id => @project, :set_filter => 1 },
:class => 'icon icon-reload' %>
<% if @query.new_record? && User.current.allowed_to?(:save_queries, @project, :global => true) %>
<%= link_to_function l(:button_save),
"$('#query_form').attr('action', '#{ @project ? new_project_query_path(@project) : new_query_path }').submit();",
:class => 'icon icon-save' %>
<% end %>
</p>
<% end %>
@@ -313,7 +326,7 @@
$(document).ready(drawGanttHandler);
$(window).resize(drawGanttHandler);
$(function() {
$("#draw_rels").change(drawGanttHandler);
$("#draw_relations").change(drawGanttHandler);
$("#draw_progress_line").change(drawGanttHandler);
});
<% end %>

View File

@@ -1,5 +1,3 @@
<h2><%= link_to l(:label_group_plural), groups_path %> &#187; <%= h(@group) %></h2>
<%= title [l(:label_group_plural), groups_path], @group.name %>
<%= render_tabs group_settings_tabs %>
<% html_title(l(:label_group), @group, l(:label_administration)) -%>

View File

@@ -2,7 +2,7 @@
<%= link_to l(:label_group_new), new_group_path, :class => 'icon icon-add' %>
</div>
<h2><%= l(:label_group_plural) %></h2>
<%= title l(:label_group_plural) %>
<% if @groups.any? %>
<table class="list groups">

View File

@@ -1,4 +1,4 @@
<h2><%= link_to l(:label_group_plural), groups_path %> &#187; <%= l(:label_group_new) %></h2>
<%= title [l(:label_group_plural), groups_path], l(:label_group_new) %>
<%= labelled_form_for @group do |f| %>
<%= render :partial => 'form', :locals => { :f => f } %>

View File

@@ -1,4 +1,4 @@
<h2><%= link_to l(:label_group_plural), groups_path %> &#187; <%=h @group %></h2>
<%= title [l(:label_group_plural), groups_path], @group.name %>
<ul>
<% @group.users.each do |user| %>

View File

@@ -4,3 +4,4 @@ $('#relations').html('<%= escape_javascript(render :partial => 'issues/relations
$('#relation_issue_to_id').val('');
$('#relation_issue_to_id').focus();
<% end %>
$('#new-relation-form').show();

View File

@@ -1,4 +1,4 @@
<h2><%= link_to l(:label_issue_status_plural), issue_statuses_path %> &#187; <%=h @issue_status %></h2>
<%= title [l(:label_issue_status_plural), issue_statuses_path], @issue_status.name %>
<%= labelled_form_for @issue_status do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>

View File

@@ -1,4 +1,4 @@
<h2><%= link_to l(:label_issue_status_plural), issue_statuses_path %> &#187; <%=l(:label_issue_status_new)%></h2>
<%= title [l(:label_issue_status_plural), issue_statuses_path], l(:label_issue_status_new) %>
<%= labelled_form_for @issue_status do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>

Some files were not shown because too many files have changed in this diff Show More