##// END OF EJS Templates
Added mail notification when a new message is posted in the forums....
Jean-Philippe Lang -
r528:7ca7e4bad503
parent child
Show More
@@ -0,0 +1,24
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 class MessageObserver < ActiveRecord::Observer
19 def after_create(message)
20 # send notification to board watchers
21 recipients = message.board.watcher_recipients
22 Mailer.deliver_message_posted(message, recipients) unless recipients.empty?
23 end
24 end
@@ -0,0 +1,4
1 <%= l(:field_author) %>: <%= @message.author.name %>
2 <%= url_for :only_path => false, :host => Setting.host_name, :controller => 'messages', :action => 'show', :board_id => @message.board_id, :id => @message.root %>
3
4 <%= @message.content %>
@@ -1,90 +1,98
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class Mailer < ActionMailer::Base
19 19 helper IssuesHelper
20 20
21 21 def issue_add(issue)
22 22 set_language_if_valid(Setting.default_language)
23 23 # Sends to all project members
24 24 @recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }.compact
25 25 @from = Setting.mail_from
26 26 @subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}"
27 27 @body['issue'] = issue
28 28 end
29 29
30 30 def issue_edit(journal)
31 31 set_language_if_valid(Setting.default_language)
32 32 # Sends to all project members
33 33 issue = journal.journalized
34 34 @recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }.compact
35 35 # Watchers in cc
36 36 @cc = issue.watcher_recipients - @recipients
37 37 @from = Setting.mail_from
38 38 @subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}"
39 39 @body['issue'] = issue
40 40 @body['journal']= journal
41 41 end
42 42
43 43 def document_add(document)
44 44 set_language_if_valid(Setting.default_language)
45 45 @recipients = document.project.users.collect { |u| u.mail if u.mail_notification }.compact
46 46 @from = Setting.mail_from
47 47 @subject = "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
48 48 @body['document'] = document
49 49 end
50 50
51 51 def attachments_add(attachments)
52 52 set_language_if_valid(Setting.default_language)
53 53 container = attachments.first.container
54 54 url = "http://#{Setting.host_name}/"
55 55 added_to = ""
56 56 case container.class.to_s
57 57 when 'Version'
58 58 url << "projects/list_files/#{container.project_id}"
59 59 added_to = "#{l(:label_version)}: #{container.name}"
60 60 when 'Document'
61 61 url << "documents/show/#{container.id}"
62 62 added_to = "#{l(:label_document)}: #{container.title}"
63 63 when 'Issue'
64 64 url << "issues/show/#{container.id}"
65 65 added_to = "#{container.tracker.name} ##{container.id}: #{container.subject}"
66 66 end
67 67 @recipients = container.project.users.collect { |u| u.mail if u.mail_notification }.compact
68 68 @from = Setting.mail_from
69 69 @subject = "[#{container.project.name}] #{l(:label_attachment_new)}"
70 70 @body['attachments'] = attachments
71 71 @body['url'] = url
72 72 @body['added_to'] = added_to
73 73 end
74 74
75 75 def lost_password(token)
76 76 set_language_if_valid(token.user.language)
77 77 @recipients = token.user.mail
78 78 @from = Setting.mail_from
79 79 @subject = l(:mail_subject_lost_password)
80 80 @body['token'] = token
81 81 end
82 82
83 83 def register(token)
84 84 set_language_if_valid(token.user.language)
85 85 @recipients = token.user.mail
86 86 @from = Setting.mail_from
87 87 @subject = l(:mail_subject_register)
88 88 @body['token'] = token
89 89 end
90
91 def message_posted(message, recipients)
92 set_language_if_valid(Setting.default_language)
93 @recipients = recipients
94 @from = Setting.mail_from
95 @subject = "[#{message.board.project.name} - #{message.board.name}] #{message.subject}"
96 @body['message'] = message
97 end
90 98 end
@@ -1,86 +1,87
1 1 # Be sure to restart your web server when you modify this file.
2 2
3 3 # Uncomment below to force Rails into production mode when
4 4 # you don't control web/app server and can't set it the proper way
5 5 # ENV['RAILS_ENV'] ||= 'production'
6 6
7 7 # Bootstrap the Rails environment, frameworks, and default configuration
8 8 require File.join(File.dirname(__FILE__), 'boot')
9 9
10 10 Rails::Initializer.run do |config|
11 11 # Settings in config/environments/* take precedence those specified here
12 12
13 13 # Skip frameworks you're not going to use
14 14 # config.frameworks -= [ :action_web_service, :action_mailer ]
15 15
16 16 # Add additional load paths for sweepers
17 17 config.load_paths += %W( #{RAILS_ROOT}/app/sweepers )
18 18
19 19 # Force all environments to use the same logger level
20 20 # (by default production uses :info, the others :debug)
21 21 # config.log_level = :debug
22 22
23 23 # Use the database for sessions instead of the file system
24 24 # (create the session table with 'rake create_sessions_table')
25 25 # config.action_controller.session_store = :active_record_store
26 26
27 27 # Enable page/fragment caching by setting a file-based store
28 28 # (remember to create the caching directory and make it readable to the application)
29 29 # config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/cache"
30
30
31 31 # Activate observers that should always be running
32 32 # config.active_record.observers = :cacher, :garbage_collector
33 config.active_record.observers = :message_observer
33 34
34 35 # Make Active Record use UTC-base instead of local time
35 36 # config.active_record.default_timezone = :utc
36 37
37 38 # Use Active Record's schema dumper instead of SQL when creating the test database
38 39 # (enables use of different database adapters for development and test environments)
39 40 # config.active_record.schema_format = :ruby
40 41
41 42 # See Rails::Configuration for more options
42 43
43 44 # SMTP server configuration
44 45 config.action_mailer.smtp_settings = {
45 46 :address => "127.0.0.1",
46 47 :port => 25,
47 48 :domain => "somenet.foo",
48 49 :authentication => :login,
49 50 :user_name => "redmine",
50 51 :password => "redmine",
51 52 }
52 53
53 54 config.action_mailer.perform_deliveries = true
54 55
55 56 # Tell ActionMailer not to deliver emails to the real world.
56 57 # The :test delivery method accumulates sent emails in the
57 58 # ActionMailer::Base.deliveries array.
58 59 #config.action_mailer.delivery_method = :test
59 60 config.action_mailer.delivery_method = :smtp
60 61 end
61 62
62 63 ActiveRecord::Errors.default_error_messages = {
63 64 :inclusion => "activerecord_error_inclusion",
64 65 :exclusion => "activerecord_error_exclusion",
65 66 :invalid => "activerecord_error_invalid",
66 67 :confirmation => "activerecord_error_confirmation",
67 68 :accepted => "activerecord_error_accepted",
68 69 :empty => "activerecord_error_empty",
69 70 :blank => "activerecord_error_blank",
70 71 :too_long => "activerecord_error_too_long",
71 72 :too_short => "activerecord_error_too_short",
72 73 :wrong_length => "activerecord_error_wrong_length",
73 74 :taken => "activerecord_error_taken",
74 75 :not_a_number => "activerecord_error_not_a_number"
75 76 }
76 77
77 78 ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "#{html_tag}" }
78 79
79 80 GLoc.set_config :default_language => :en
80 81 GLoc.clear_strings
81 82 GLoc.set_kcode
82 83 GLoc.load_localized_strings
83 84 GLoc.set_config(:raise_string_not_found_errors => false)
84 85
85 86 require 'redmine'
86 87
@@ -1,230 +1,231
1 1 # Copyright (c) 2005-2006 David Barri
2 2
3 3 require 'gloc'
4 4
5 5 module ActionController #:nodoc:
6 6 class Base #:nodoc:
7 7 include GLoc
8 8 end
9 9 module Filters #:nodoc:
10 10 module ClassMethods
11 11
12 12 # This filter attempts to auto-detect the clients desired language.
13 13 # It first checks the params, then a cookie and then the HTTP_ACCEPT_LANGUAGE
14 14 # request header. If a language is found to match or be similar to a currently
15 15 # valid language, then it sets the current_language of the controller.
16 16 #
17 17 # class ExampleController < ApplicationController
18 18 # set_language :en
19 19 # autodetect_language_filter :except => 'monkey', :on_no_lang => :lang_not_autodetected_callback
20 20 # autodetect_language_filter :only => 'monkey', :check_cookie => 'monkey_lang', :check_accept_header => false
21 21 # ...
22 22 # def lang_not_autodetected_callback
23 23 # redirect_to somewhere
24 24 # end
25 25 # end
26 26 #
27 27 # The <tt>args</tt> for this filter are exactly the same the arguments of
28 28 # <tt>before_filter</tt> with the following exceptions:
29 29 # * <tt>:check_params</tt> -- If false, then params will not be checked for a language.
30 30 # If a String, then this will value will be used as the name of the param.
31 31 # * <tt>:check_cookie</tt> -- If false, then the cookie will not be checked for a language.
32 32 # If a String, then this will value will be used as the name of the cookie.
33 33 # * <tt>:check_accept_header</tt> -- If false, then HTTP_ACCEPT_LANGUAGE will not be checked for a language.
34 34 # * <tt>:on_set_lang</tt> -- You can specify the name of a callback function to be called when the language
35 35 # is successfully detected and set. The param must be a Symbol or a String which is the name of the function.
36 36 # The callback function must accept one argument (the language) and must be instance level.
37 37 # * <tt>:on_no_lang</tt> -- You can specify the name of a callback function to be called when the language
38 38 # couldn't be detected automatically. The param must be a Symbol or a String which is the name of the function.
39 39 # The callback function must be instance level.
40 40 #
41 41 # You override the default names of the param or cookie by calling <tt>GLoc.set_config :default_param_name => 'new_param_name'</tt>
42 42 # and <tt>GLoc.set_config :default_cookie_name => 'new_cookie_name'</tt>.
43 43 def autodetect_language_filter(*args)
44 44 options= args.last.is_a?(Hash) ? args.last : {}
45 45 x= 'Proc.new { |c| l= nil;'
46 46 # :check_params
47 47 unless (v= options.delete(:check_params)) == false
48 48 name= v ? ":#{v}" : 'GLoc.get_config(:default_param_name)'
49 49 x << "l ||= GLoc.similar_language(c.params[#{name}]);"
50 50 end
51 51 # :check_cookie
52 52 unless (v= options.delete(:check_cookie)) == false
53 53 name= v ? ":#{v}" : 'GLoc.get_config(:default_cookie_name)'
54 54 x << "l ||= GLoc.similar_language(c.send(:cookies)[#{name}]);"
55 55 end
56 56 # :check_accept_header
57 57 unless options.delete(:check_accept_header) == false
58 58 x << %<
59 59 unless l
60 60 a= c.request.env['HTTP_ACCEPT_LANGUAGE'].split(/,|;/) rescue nil
61 61 a.each {|x| l ||= GLoc.similar_language(x)} if a
62 62 end; >
63 63 end
64 64 # Set language
65 65 x << 'ret= true;'
66 66 x << 'if l; c.set_language(l); c.headers[\'Content-Language\']= l.to_s; '
67 67 if options.has_key?(:on_set_lang)
68 68 x << "ret= c.#{options.delete(:on_set_lang)}(l);"
69 69 end
70 70 if options.has_key?(:on_no_lang)
71 71 x << "else; ret= c.#{options.delete(:on_no_lang)};"
72 72 end
73 73 x << 'end; ret }'
74 74
75 75 # Create filter
76 76 block= eval x
77 77 before_filter(*args, &block)
78 78 end
79 79
80 80 end
81 81 end
82 82 end
83 83
84 84 # ==============================================================================
85 85
86 86 module ActionMailer #:nodoc:
87 87 # In addition to including GLoc, <tt>render_message</tt> is also overridden so
88 88 # that mail templates contain the current language at the end of the file.
89 89 # Eg. <tt>deliver_hello</tt> will render <tt>hello_en.rhtml</tt>.
90 90 class Base
91 91 include GLoc
92 92 private
93 93 alias :render_message_without_gloc :render_message
94 94 def render_message(method_name, body)
95 render_message_without_gloc("#{method_name}_#{current_language}", body)
95 template = File.exist?("#{template_path}/#{method_name}_#{current_language}.rhtml") ? "#{method_name}_#{current_language}" : "#{method_name}"
96 render_message_without_gloc(template, body)
96 97 end
97 98 end
98 99 end
99 100
100 101 # ==============================================================================
101 102
102 103 module ActionView #:nodoc:
103 104 # <tt>initialize</tt> is overridden so that new instances of this class inherit
104 105 # the current language of the controller.
105 106 class Base
106 107 include GLoc
107 108
108 109 alias :initialize_without_gloc :initialize
109 110 def initialize(base_path = nil, assigns_for_first_render = {}, controller = nil)
110 111 initialize_without_gloc(base_path, assigns_for_first_render, controller)
111 112 set_language controller.current_language unless controller.nil?
112 113 end
113 114 end
114 115
115 116 module Helpers #:nodoc:
116 117 class InstanceTag
117 118 include GLoc
118 119 # Inherits the current language from the template object.
119 120 def current_language
120 121 @template_object.current_language
121 122 end
122 123 end
123 124 end
124 125 end
125 126
126 127 # ==============================================================================
127 128
128 129 module ActiveRecord #:nodoc:
129 130 class Base #:nodoc:
130 131 include GLoc
131 132 end
132 133
133 134 # class Errors
134 135 # include GLoc
135 136 # alias :add_without_gloc :add
136 137 # # The GLoc version of this method provides two extra features
137 138 # # * If <tt>msg</tt> is a string, it will be considered a GLoc string key.
138 139 # # * If <tt>msg</tt> is an array, the first element will be considered
139 140 # # the string and the remaining elements will be considered arguments for the
140 141 # # string. Eg. <tt>['Hi %s.','John']</tt>
141 142 # def add(attribute, msg= @@default_error_messages[:invalid])
142 143 # if msg.is_a?(Array)
143 144 # args= msg.clone
144 145 # msg= args.shift
145 146 # args= nil if args.empty?
146 147 # end
147 148 # msg= ltry(msg)
148 149 # msg= msg % args unless args.nil?
149 150 # add_without_gloc(attribute, msg)
150 151 # end
151 152 # # Inherits the current language from the base record.
152 153 # def current_language
153 154 # @base.current_language
154 155 # end
155 156 # end
156 157
157 158 module Validations #:nodoc:
158 159 module ClassMethods
159 160 # The default Rails version of this function creates an error message and then
160 161 # passes it to ActiveRecord.Errors.
161 162 # The GLoc version of this method, sends an array to ActiveRecord.Errors that will
162 163 # be turned into a string by ActiveRecord.Errors which in turn allows for the message
163 164 # of this validation function to be a GLoc string key.
164 165 def validates_length_of(*attrs)
165 166 # Merge given options with defaults.
166 167 options = {
167 168 :too_long => ActiveRecord::Errors.default_error_messages[:too_long],
168 169 :too_short => ActiveRecord::Errors.default_error_messages[:too_short],
169 170 :wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length]
170 171 }.merge(DEFAULT_VALIDATION_OPTIONS)
171 172 options.update(attrs.pop.symbolize_keys) if attrs.last.is_a?(Hash)
172 173
173 174 # Ensure that one and only one range option is specified.
174 175 range_options = ALL_RANGE_OPTIONS & options.keys
175 176 case range_options.size
176 177 when 0
177 178 raise ArgumentError, 'Range unspecified. Specify the :within, :maximum, :minimum, or :is option.'
178 179 when 1
179 180 # Valid number of options; do nothing.
180 181 else
181 182 raise ArgumentError, 'Too many range options specified. Choose only one.'
182 183 end
183 184
184 185 # Get range option and value.
185 186 option = range_options.first
186 187 option_value = options[range_options.first]
187 188
188 189 case option
189 190 when :within, :in
190 191 raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range)
191 192
192 193 too_short = [options[:too_short] , option_value.begin]
193 194 too_long = [options[:too_long] , option_value.end ]
194 195
195 196 validates_each(attrs, options) do |record, attr, value|
196 197 if value.nil? or value.split(//).size < option_value.begin
197 198 record.errors.add(attr, too_short)
198 199 elsif value.split(//).size > option_value.end
199 200 record.errors.add(attr, too_long)
200 201 end
201 202 end
202 203 when :is, :minimum, :maximum
203 204 raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?(Integer) and option_value >= 0
204 205
205 206 # Declare different validations per option.
206 207 validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" }
207 208 message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }
208 209
209 210 message = [(options[:message] || options[message_options[option]]) , option_value]
210 211
211 212 validates_each(attrs, options) do |record, attr, value|
212 213 if value.kind_of?(String)
213 214 record.errors.add(attr, message) unless !value.nil? and value.split(//).size.method(validity_checks[option])[option_value]
214 215 else
215 216 record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value]
216 217 end
217 218 end
218 219 end
219 220 end
220 221
221 222 alias_method :validates_size_of, :validates_length_of
222 223 end
223 224 end
224 225 end
225 226
226 227 # ==============================================================================
227 228
228 229 module ApplicationHelper #:nodoc:
229 230 include GLoc
230 231 end
General Comments 0
You need to be logged in to leave comments. Login now