Commit 90d33c3e authored by Jean-Philippe Lang's avatar Jean-Philippe Lang

More flexible mail notifications settings at user level. A user has now 3 options:

* notification on any event on all his projects
* notification on any event on selected projects only (if the user belongs to more than 1 project)
* notification only for things that he watches or he is involded in (eg. issues that he watches or he is author or assignee)

git-svn-id: http://redmine.rubyforge.org/svn/trunk@855 e93f8b46-1217-0410-a6f0-8f06a7374b81
parent eacd0506
...@@ -50,32 +50,44 @@ class MyController < ApplicationController ...@@ -50,32 +50,44 @@ class MyController < ApplicationController
# Edit user's account # Edit user's account
def account def account
@user = self.logged_in_user @user = User.current
@pref = @user.pref @pref = @user.pref
@user.attributes = params[:user] if request.post?
@user.pref.attributes = params[:pref] @user.attributes = params[:user]
if request.post? && @user.save && @user.pref.save @user.mail_notification = (params[:notification_option] == 'all')
flash[:notice] = l(:notice_account_updated) @user.pref.attributes = params[:pref]
redirect_to :action => 'account' if @user.save
@user.pref.save
@user.notified_project_ids = (params[:notification_option] == 'selected' ? params[:notified_project_ids] : [])
set_language_if_valid @user.language
flash[:notice] = l(:notice_account_updated)
redirect_to :action => 'account'
return
end
end end
@notification_options = [[l(:label_user_mail_option_all), 'all'],
[l(:label_user_mail_option_none), 'none']]
# Only users that belong to more than 1 project can select projects for which they are notified
# Note that @user.membership.size would fail since AR ignores :include association option when doing a count
@notification_options.insert 1, [l(:label_user_mail_option_selected), 'selected'] if @user.memberships.length > 1
@notification_option = @user.mail_notification? ? 'all' : (@user.notified_projects_ids.empty? ? 'none' : 'selected')
end end
# Change user's password # Manage user's password
def change_password def password
@user = self.logged_in_user @user = self.logged_in_user
flash[:error] = l(:notice_can_t_change_password) and redirect_to :action => 'account' and return if @user.auth_source_id flash[:error] = l(:notice_can_t_change_password) and redirect_to :action => 'account' and return if @user.auth_source_id
if @user.check_password?(params[:password]) if request.post?
@user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] if @user.check_password?(params[:password])
if @user.save @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
flash[:notice] = l(:notice_account_password_updated) if @user.save
flash[:notice] = l(:notice_account_password_updated)
redirect_to :action => 'account'
end
else else
render :action => 'account' flash[:error] = l(:notice_account_wrong_password)
return
end end
else
flash[:error] = l(:notice_account_wrong_password)
end end
redirect_to :action => 'account'
end end
# Create a new feeds key # Create a new feeds key
......
...@@ -143,6 +143,15 @@ class Issue < ActiveRecord::Base ...@@ -143,6 +143,15 @@ class Issue < ActiveRecord::Base
project.assignable_users project.assignable_users
end end
# Returns the mail adresses of users that should be notified for the issue
def recipients
recipients = project.recipients
# Author and assignee are always notified
recipients << author.mail if author
recipients << assigned_to.mail if assigned_to
recipients.compact.uniq
end
def spent_hours def spent_hours
@spent_hours ||= time_entries.sum(:hours) || 0 @spent_hours ||= time_entries.sum(:hours) || 0
end end
......
...@@ -30,13 +30,7 @@ class Mailer < ActionMailer::Base ...@@ -30,13 +30,7 @@ class Mailer < ActionMailer::Base
def issue_add(issue) def issue_add(issue)
set_language_if_valid(Setting.default_language) set_language_if_valid(Setting.default_language)
# Sends to all project members @recipients = issue.recipients
@recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }.compact
# Sends to author and assignee (even if they turned off mail notification)
@recipients << issue.author.mail if issue.author
@recipients << issue.assigned_to.mail if issue.assigned_to
@recipients.compact!
@recipients.uniq!
@from = Setting.mail_from @from = Setting.mail_from
@subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}" @subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}"
@body['issue'] = issue @body['issue'] = issue
...@@ -44,14 +38,8 @@ class Mailer < ActionMailer::Base ...@@ -44,14 +38,8 @@ class Mailer < ActionMailer::Base
def issue_edit(journal) def issue_edit(journal)
set_language_if_valid(Setting.default_language) set_language_if_valid(Setting.default_language)
# Sends to all project members
issue = journal.journalized issue = journal.journalized
@recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }.compact @recipients = issue.recipients
# Sends to author and assignee (even if they turned off mail notification)
@recipients << issue.author.mail if issue.author
@recipients << issue.assigned_to.mail if issue.assigned_to
@recipients.compact!
@recipients.uniq!
# Watchers in cc # Watchers in cc
@cc = issue.watcher_recipients - @recipients @cc = issue.watcher_recipients - @recipients
@from = Setting.mail_from @from = Setting.mail_from
...@@ -62,7 +50,7 @@ class Mailer < ActionMailer::Base ...@@ -62,7 +50,7 @@ class Mailer < ActionMailer::Base
def document_added(document) def document_added(document)
set_language_if_valid(Setting.default_language) set_language_if_valid(Setting.default_language)
@recipients = document.project.users.collect { |u| u.mail if u.mail_notification }.compact @recipients = document.project.recipients
@from = Setting.mail_from @from = Setting.mail_from
@subject = "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}" @subject = "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
@body['document'] = document @body['document'] = document
...@@ -81,7 +69,7 @@ class Mailer < ActionMailer::Base ...@@ -81,7 +69,7 @@ class Mailer < ActionMailer::Base
url = {:only_path => false, :host => Setting.host_name, :controller => 'documents', :action => 'show', :id => container.id} url = {:only_path => false, :host => Setting.host_name, :controller => 'documents', :action => 'show', :id => container.id}
added_to = "#{l(:label_document)}: #{container.title}" added_to = "#{l(:label_document)}: #{container.title}"
end end
@recipients = container.project.users.collect { |u| u.mail if u.mail_notification }.compact @recipients = container.project.recipients
@from = Setting.mail_from @from = Setting.mail_from
@subject = "[#{container.project.name}] #{l(:label_attachment_new)}" @subject = "[#{container.project.name}] #{l(:label_attachment_new)}"
@body['attachments'] = attachments @body['attachments'] = attachments
...@@ -91,7 +79,7 @@ class Mailer < ActionMailer::Base ...@@ -91,7 +79,7 @@ class Mailer < ActionMailer::Base
def news_added(news) def news_added(news)
set_language_if_valid(Setting.default_language) set_language_if_valid(Setting.default_language)
@recipients = news.project.users.collect { |u| u.mail if u.mail_notification }.compact @recipients = news.project.recipients
@from = Setting.mail_from @from = Setting.mail_from
@subject = "[#{news.project.name}] #{l(:label_news)}: #{news.title}" @subject = "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
@body['news'] = news @body['news'] = news
......
...@@ -118,6 +118,11 @@ class Project < ActiveRecord::Base ...@@ -118,6 +118,11 @@ class Project < ActiveRecord::Base
members.select {|m| m.role.assignable?}.collect {|m| m.user} members.select {|m| m.role.assignable?}.collect {|m| m.user}
end end
# Returns the mail adresses of users that should be always notified on project events
def recipients
members.select {|m| m.mail_notification? || m.user.mail_notification?}.collect {|m| m.user.mail}
end
# Returns an array of all custom fields enabled for project issues # Returns an array of all custom fields enabled for project issues
# (explictly associated custom fields and custom fields enabled for all projects) # (explictly associated custom fields and custom fields enabled for all projects)
def custom_fields_for_issues(tracker) def custom_fields_for_issues(tracker)
......
...@@ -50,6 +50,11 @@ class User < ActiveRecord::Base ...@@ -50,6 +50,11 @@ class User < ActiveRecord::Base
validates_confirmation_of :password, :allow_nil => true validates_confirmation_of :password, :allow_nil => true
validates_associated :custom_values, :on => :update validates_associated :custom_values, :on => :update
def before_create
self.mail_notification = false
true
end
def before_save def before_save
# update hashed_password if password was set # update hashed_password if password was set
self.hashed_password = User.hash_password(self.password) if self.password self.hashed_password = User.hash_password(self.password) if self.password
...@@ -131,6 +136,18 @@ class User < ActiveRecord::Base ...@@ -131,6 +136,18 @@ class User < ActiveRecord::Base
token.value token.value
end end
# Return an array of project ids for which the user has explicitly turned mail notifications on
def notified_projects_ids
@notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)
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
end
def self.find_by_rss_key(key) def self.find_by_rss_key(key)
token = Token.find_by_value(key) token = Token.find_by_value(key)
token && token.user.active? ? token.user : nil token && token.user.active? ? token.user : nil
......
<h3><%=l(:label_my_account)%></h3>
<p><%=l(:field_login)%>: <strong><%= @user.login %></strong><br />
<%=l(:field_created_on)%>: <%= format_time(@user.created_on) %></p>
<% if @user.rss_token %>
<p><%= l(:label_feeds_access_key_created_on, distance_of_time_in_words(Time.now, @user.rss_token.created_on)) %>
(<%= link_to l(:button_reset), {:action => 'reset_rss_key'}, :method => :post %>)</p>
<% end %>
<div class="contextual">
<%= link_to(l(:button_change_password), :action => 'password') unless @user.auth_source_id %>
</div>
<h2><%=l(:label_my_account)%></h2> <h2><%=l(:label_my_account)%></h2>
<%= error_messages_for 'user' %> <%= error_messages_for 'user' %>
<div class="box"> <% form_for :user, @user, :url => { :action => "account" }, :builder => TabularFormBuilder, :lang => current_language do |f| %>
<div class="splitcontentleft">
<h3><%=l(:label_information_plural)%></h3> <h3><%=l(:label_information_plural)%></h3>
<div class="box tabular">
<% labelled_tabular_form_for :user, @user, :url => { :action => "account" } do |f| %>
<p><%= f.text_field :firstname, :required => true %></p> <p><%= f.text_field :firstname, :required => true %></p>
<p><%= f.text_field :lastname, :required => true %></p> <p><%= f.text_field :lastname, :required => true %></p>
<p><%= f.text_field :mail, :required => true, :size => 40 %></p> <p><%= f.text_field :mail, :required => true %></p>
<p><%= f.select :language, lang_options_for_select %></p> <p><%= f.select :language, lang_options_for_select %></p>
<p><%= f.check_box :mail_notification %></p>
<% fields_for :pref, @user.pref, :builder => TabularFormBuilder, :lang => current_language do |pref_fields| %> <% fields_for :pref, @user.pref, :builder => TabularFormBuilder, :lang => current_language do |pref_fields| %>
<p><%= pref_fields.check_box :hide_mail %></p> <p><%= pref_fields.check_box :hide_mail %></p>
<% end %> <% end %>
<center><%= submit_tag l(:button_save) %></center>
<% end %>
</div> </div>
<%= submit_tag l(:button_save) %>
</div>
<% unless @user.auth_source_id %> <div class="splitcontentright">
<div class="box"> <h3><%=l(:field_mail_notification)%></h3>
<h3><%=l(:field_password)%></h3> <div class="box">
<%= select_tag 'notification_option', options_for_select(@notification_options, @notification_option),
<% form_tag({:action => 'change_password'}, :class => "tabular") do %> :onchange => 'if ($("notification_option").value == "selected") {Element.show("notified-projects")} else {Element.hide("notified-projects")}' %>
<% content_tag 'div', :id => 'notified-projects', :style => (@notification_option == 'selected' ? '' : 'display:none;') do %>
<p><label for="password"><%=l(:field_password)%> <span class="required">*</span></label> <p><% User.current.projects.each do |project| %>
<%= password_field_tag 'password', nil, :size => 25 %></p> <label><%= check_box_tag 'notified_project_ids[]', project.id, @user.notified_projects_ids.include?(project.id) %> <%= project.name %></label><br />
<% end %></p>
<p><label for="new_password"><%=l(:field_new_password)%> <span class="required">*</span></label> <p><em><%= l(:text_user_mail_option) %></em></p>
<%= password_field_tag 'new_password', nil, :size => 25 %><br /> <% end %>
<em><%= l(:text_length_between, 4, 12) %></em></p> </div>
</div>
<p><label for="new_password_confirmation"><%=l(:field_password_confirmation)%> <span class="required">*</span></label>
<%= password_field_tag 'new_password_confirmation', nil, :size => 25 %></p>
<center><%= submit_tag l(:button_save) %></center>
<% end %>
</div>
<% end %> <% end %>
<% content_for :sidebar do %> <% content_for :sidebar do %>
<h3><%=l(:label_my_account)%></h3> <%= render :partial => 'sidebar' %>
<p><%=l(:field_login)%>: <strong><%= @user.login %></strong><br />
<%=l(:field_created_on)%>: <%= format_time(@user.created_on) %></p>
<% if @user.rss_token %>
<p><%= l(:label_feeds_access_key_created_on, distance_of_time_in_words(Time.now, @user.rss_token.created_on)) %>
(<%= link_to l(:button_reset), {:action => 'reset_rss_key'}, :method => :post %>)</p>
<% end %>
<% end %> <% end %>
<h2><%=l(:button_change_password)%></h2>
<%= error_messages_for 'user' %>
<% form_tag({}, :class => "tabular") do %>
<div class="box">
<p><label for="password"><%=l(:field_password)%> <span class="required">*</span></label>
<%= password_field_tag 'password', nil, :size => 25 %></p>
<p><label for="new_password"><%=l(:field_new_password)%> <span class="required">*</span></label>
<%= password_field_tag 'new_password', nil, :size => 25 %><br />
<em><%= l(:text_length_between, 4, 12) %></em></p>
<p><label for="new_password_confirmation"><%=l(:field_password_confirmation)%> <span class="required">*</span></label>
<%= password_field_tag 'new_password_confirmation', nil, :size => 25 %></p>
</div>
<%= submit_tag l(:button_apply) %>
<% end %>
<% content_for :sidebar do %>
<%= render :partial => 'sidebar' %>
<% end %>
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
<% end if @custom_values%> <% end if @custom_values%>
<p><%= f.check_box :admin %></p> <p><%= f.check_box :admin %></p>
<p><%= f.check_box :mail_notification %></p>
</div> </div>
<div class="box"> <div class="box">
......
...@@ -284,7 +284,7 @@ class Setup < ActiveRecord::Migration ...@@ -284,7 +284,7 @@ class Setup < ActiveRecord::Migration
Permission.create :controller => "versions", :action => "destroy_file", :description => "button_delete", :sort => 1322 Permission.create :controller => "versions", :action => "destroy_file", :description => "button_delete", :sort => 1322
# create default administrator account # create default administrator account
user = User.create :firstname => "redMine", :lastname => "Admin", :mail => "admin@somenet.foo", :mail_notification => true, :language => "en" user = User.create :firstname => "Redmine", :lastname => "Admin", :mail => "admin@somenet.foo", :mail_notification => true, :language => "en"
user.login = "admin" user.login = "admin"
user.password = "admin" user.password = "admin"
user.admin = true user.admin = true
......
class AddMembersMailNotification < ActiveRecord::Migration
def self.up
add_column :members, :mail_notification, :boolean, :default => false, :null => false
end
def self.down
remove_column :members, :mail_notification
end
end
...@@ -526,3 +526,8 @@ label_theme: Тема ...@@ -526,3 +526,8 @@ label_theme: Тема
label_default: По подразбиране label_default: По подразбиране
label_search_titles_only: Само в заглавията label_search_titles_only: Само в заглавията
label_nobody: nobody label_nobody: nobody
button_change_password: Change password
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "Only for things I watch or I'm involved in"
...@@ -526,3 +526,8 @@ label_theme: Theme ...@@ -526,3 +526,8 @@ label_theme: Theme
label_default: Default label_default: Default
label_search_titles_only: Search titles only label_search_titles_only: Search titles only
label_nobody: nobody label_nobody: nobody
button_change_password: Change password
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "Only for things I watch or I'm involved in"
...@@ -526,3 +526,8 @@ label_theme: Theme ...@@ -526,3 +526,8 @@ label_theme: Theme
label_default: Default label_default: Default
label_search_titles_only: Search titles only label_search_titles_only: Search titles only
label_nobody: nobody label_nobody: nobody
button_change_password: Change password
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "Only for things I watch or I'm involved in"
...@@ -127,7 +127,7 @@ field_parent: Subproject of ...@@ -127,7 +127,7 @@ field_parent: Subproject of
field_is_in_chlog: Issues displayed in changelog field_is_in_chlog: Issues displayed in changelog
field_is_in_roadmap: Issues displayed in roadmap field_is_in_roadmap: Issues displayed in roadmap
field_login: Login field_login: Login
field_mail_notification: Mail notifications field_mail_notification: Email notifications
field_admin: Administrator field_admin: Administrator
field_last_login_on: Last connection field_last_login_on: Last connection
field_language: Language field_language: Language
...@@ -174,7 +174,7 @@ setting_login_required: Authent. required ...@@ -174,7 +174,7 @@ setting_login_required: Authent. required
setting_self_registration: Self-registration enabled setting_self_registration: Self-registration enabled
setting_attachment_max_size: Attachment max. size setting_attachment_max_size: Attachment max. size
setting_issues_export_limit: Issues export limit setting_issues_export_limit: Issues export limit
setting_mail_from: Emission mail address setting_mail_from: Emission email address
setting_host_name: Host name setting_host_name: Host name
setting_text_formatting: Text formatting setting_text_formatting: Text formatting
setting_wiki_compression: Wiki history compression setting_wiki_compression: Wiki history compression
...@@ -437,6 +437,9 @@ label_bulk_edit_selected_issues: Bulk edit selected issues ...@@ -437,6 +437,9 @@ label_bulk_edit_selected_issues: Bulk edit selected issues
label_theme: Theme label_theme: Theme
label_default: Default label_default: Default
label_search_titles_only: Search titles only label_search_titles_only: Search titles only
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_none: "Only for things I watch or I'm involved in"
button_login: Login button_login: Login
button_submit: Submit button_submit: Submit
...@@ -470,12 +473,13 @@ button_archive: Archive ...@@ -470,12 +473,13 @@ button_archive: Archive
button_unarchive: Unarchive button_unarchive: Unarchive
button_reset: Reset button_reset: Reset
button_rename: Rename button_rename: Rename
button_change_password: Change password
status_active: active status_active: active
status_registered: registered status_registered: registered
status_locked: locked status_locked: locked
text_select_mail_notifications: Select actions for which mail notifications should be sent. text_select_mail_notifications: Select actions for which email notifications should be sent.
text_regexp_info: eg. ^[A-Z0-9]+$ text_regexp_info: eg. ^[A-Z0-9]+$
text_min_max_length_info: 0 means no restriction text_min_max_length_info: 0 means no restriction
text_project_destroy_confirmation: Are you sure you want to delete this project and all related data ? text_project_destroy_confirmation: Are you sure you want to delete this project and all related data ?
...@@ -500,6 +504,7 @@ text_wiki_destroy_confirmation: Are you sure you want to delete this wiki and al ...@@ -500,6 +504,7 @@ text_wiki_destroy_confirmation: Are you sure you want to delete this wiki and al
text_issue_category_destroy_question: Some issues (%d) are assigned to this category. What do you want to do ? text_issue_category_destroy_question: Some issues (%d) are assigned to this category. What do you want to do ?
text_issue_category_destroy_assignments: Remove category assignments text_issue_category_destroy_assignments: Remove category assignments
text_issue_category_reassign_to: Reassign issues to this category text_issue_category_reassign_to: Reassign issues to this category
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
default_role_manager: Manager default_role_manager: Manager
default_role_developper: Developer default_role_developper: Developer
......
...@@ -529,3 +529,8 @@ label_theme: Theme ...@@ -529,3 +529,8 @@ label_theme: Theme
label_default: Default label_default: Default
label_search_titles_only: Search titles only label_search_titles_only: Search titles only
label_nobody: nobody label_nobody: nobody
button_change_password: Change password
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "Only for things I watch or I'm involved in"
...@@ -437,6 +437,9 @@ label_bulk_edit_selected_issues: Modifier les demandes sélectionnées ...@@ -437,6 +437,9 @@ label_bulk_edit_selected_issues: Modifier les demandes sélectionnées
label_theme: Thème label_theme: Thème
label_default: Défaut label_default: Défaut
label_search_titles_only: Uniquement dans les titres label_search_titles_only: Uniquement dans les titres
label_user_mail_option_all: "Pour tous les événements de tous mes projets"
label_user_mail_option_selected: "Pour tous les événements des projets sélectionnés..."
label_user_mail_option_none: "Seulement pour ce que je surveille ou à quoi je participe"
button_login: Connexion button_login: Connexion
button_submit: Soumettre button_submit: Soumettre
...@@ -470,6 +473,7 @@ button_archive: Archiver ...@@ -470,6 +473,7 @@ button_archive: Archiver
button_unarchive: Désarchiver button_unarchive: Désarchiver
button_reset: Réinitialiser button_reset: Réinitialiser
button_rename: Renommer button_rename: Renommer
button_change_password: Changer de mot de passe
status_active: actif status_active: actif
status_registered: enregistré status_registered: enregistré
...@@ -500,6 +504,7 @@ text_wiki_destroy_confirmation: Etes-vous sûr de vouloir supprimer ce wiki et t ...@@ -500,6 +504,7 @@ text_wiki_destroy_confirmation: Etes-vous sûr de vouloir supprimer ce wiki et t
text_issue_category_destroy_question: Des demandes (%d) sont affectées à cette catégories. Que voulez-vous faire ? text_issue_category_destroy_question: Des demandes (%d) sont affectées à cette catégories. Que voulez-vous faire ?
text_issue_category_destroy_assignments: N'affecter les demandes à aucune autre catégorie text_issue_category_destroy_assignments: N'affecter les demandes à aucune autre catégorie
text_issue_category_reassign_to: Réaffecter les demandes à cette catégorie text_issue_category_reassign_to: Réaffecter les demandes à cette catégorie
text_user_mail_option: "Pour les projets non sélectionnés, vous recevrez seulement des notifications pour ce que vous surveillez ou à quoi vous participez (exemple: demandes dont vous êtes l'auteur ou la personne assignée)."
default_role_manager: Manager default_role_manager: Manager
default_role_developper: Développeur default_role_developper: Développeur
......
...@@ -526,3 +526,8 @@ enumeration_doc_categories: קטגוריות מסמכים ...@@ -526,3 +526,8 @@ enumeration_doc_categories: קטגוריות מסמכים
enumeration_activities: פעילויות (מעקב אחר זמנים) enumeration_activities: פעילויות (מעקב אחר זמנים)
label_search_titles_only: Search titles only label_search_titles_only: Search titles only
label_nobody: nobody label_nobody: nobody
button_change_password: Change password
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "Only for things I watch or I'm involved in"
...@@ -526,3 +526,8 @@ label_theme: Theme ...@@ -526,3 +526,8 @@ label_theme: Theme
label_default: Default label_default: Default
label_search_titles_only: Search titles only label_search_titles_only: Search titles only
label_nobody: nobody label_nobody: nobody
button_change_password: Change password
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "Only for things I watch or I'm involved in"
...@@ -527,3 +527,8 @@ label_theme: テーマ ...@@ -527,3 +527,8 @@ label_theme: テーマ
label_default: 既定 label_default: 既定
label_search_titles_only: Search titles only label_search_titles_only: Search titles only
label_nobody: nobody label_nobody: nobody
button_change_password: Change password
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "Only for things I watch or I'm involved in"
...@@ -527,3 +527,8 @@ label_theme: Theme ...@@ -527,3 +527,8 @@ label_theme: Theme
label_default: Default label_default: Default
label_search_titles_only: Search titles only label_search_titles_only: Search titles only
label_nobody: nobody label_nobody: nobody
button_change_password: Change password
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "Only for things I watch or I'm involved in"
...@@ -526,3 +526,8 @@ label_theme: Temat ...@@ -526,3 +526,8 @@ label_theme: Temat
label_default: Domyślne label_default: Domyślne
label_search_titles_only: Przeszukuj tylko tytuły label_search_titles_only: Przeszukuj tylko tytuły
label_nobody: nobody label_nobody: nobody
button_change_password: Change password
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "Only for things I watch or I'm involved in"
...@@ -526,3 +526,8 @@ label_theme: Theme ...@@ -526,3 +526,8 @@ label_theme: Theme
label_default: Default label_default: Default
label_search_titles_only: Search titles only label_search_titles_only: Search titles only
label_nobody: nobody label_nobody: nobody
button_change_password: Change password
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "Only for things I watch or I'm involved in"
...@@ -526,3 +526,8 @@ label_theme: Theme ...@@ -526,3 +526,8 @@ label_theme: Theme
label_default: Default label_default: Default
label_search_titles_only: Search titles only label_search_titles_only: Search titles only
label_nobody: nobody label_nobody: nobody
button_change_password: Change password
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "Only for things I watch or I'm involved in"
...@@ -526,3 +526,8 @@ label_theme: Theme ...@@ -526,3 +526,8 @@ label_theme: Theme
label_default: Default label_default: Default
label_search_titles_only: Search titles only label_search_titles_only: Search titles only
label_nobody: nobody label_nobody: nobody
button_change_password: Change password
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "Only for things I watch or I'm involved in"
...@@ -527,3 +527,8 @@ label_theme: Theme ...@@ -527,3 +527,8 @@ label_theme: Theme
label_default: Default label_default: Default
label_search_titles_only: Search titles only label_search_titles_only: Search titles only
label_nobody: nobody label_nobody: nobody
button_change_password: Change password
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "Only for things I watch or I'm involved in"
...@@ -529,3 +529,8 @@ label_theme: Theme ...@@ -529,3 +529,8 @@ label_theme: Theme
label_default: Default label_default: Default
label_search_titles_only: Search titles only label_search_titles_only: Search titles only
label_nobody: nobody label_nobody: nobody
button_change_password: Change password
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "Only for things I watch or I'm involved in"
...@@ -116,6 +116,7 @@ textarea.wiki-edit { width: 99%; } ...@@ -116,6 +116,7 @@ textarea.wiki-edit { width: 99%; }
li p {margin-top: 0;} li p {margin-top: 0;}
div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;} div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;}
.autoscroll {overflow-x: auto; padding:1px; width:100%;} .autoscroll {overflow-x: auto; padding:1px; width:100%;}
#user_firstname, #user_lastname, #user_mail, #notification_option { width: 90%; }
/***** Tabular forms ******/ /***** Tabular forms ******/
.tabular p{ .tabular p{
......
...@@ -61,29 +61,30 @@ class MyControllerTest < Test::Unit::TestCase ...@@ -61,29 +61,30 @@ class MyControllerTest < Test::Unit::TestCase
end end
def test_change_password def test_change_password
get :account get :password
assert_response :success assert_response :success
assert_template 'account' assert_template 'password'
# non matching password confirmation # non matching password confirmation
post :change_password, :password => 'jsmith', post :password, :password => 'jsmith',
:new_password => 'hello', :new_password => 'hello',
:new_password_confirmation => 'hello2' :new_password_confirmation => 'hello2'
assert_response :success assert_response :success
assert_template 'account' assert_template 'password'
assert_tag :tag => "div", :attributes => { :class => "errorExplanation" } assert_tag :tag => "div", :attributes => { :class => "errorExplanation" }
# wrong password # wrong password
post :change_password, :password => 'wrongpassword', post :password, :password => 'wrongpassword',
:new_password => 'hello', :new_password => 'hello',
:new_password_confirmation => 'hello' :new_password_confirmation => 'hello'
assert_redirected_to 'my/account' assert_response :success
assert_template 'password'
assert_equal 'Wrong password', flash[:error] assert_equal 'Wrong password', flash[:error]
# good password # good password
post :change_password, :password => 'jsmith', post :password, :password => 'jsmith',
:new_password => 'hello', :new_password => 'hello',
:new_password_confirmation => 'hello' :new_password_confirmation => 'hello'
assert_redirected_to 'my/account' assert_redirected_to 'my/account'
assert User.try_to_login('jsmith', 'hello') assert User.try_to_login('jsmith', 'hello')
end end
......
...@@ -105,4 +105,28 @@ class UserTest < Test::Unit::TestCase ...@@ -105,4 +105,28 @@ class UserTest < Test::Unit::TestCase
# user with no role # user with no role
assert !@dlopper.role_for_project(Project.find(2)).member? assert !@dlopper.role_for_project(Project.find(2)).member?
end end
def test_mail_notification_all
@jsmith.mail_notification = true
@jsmith.notified_project_ids = []
@jsmith.save
@jsmith.reload
assert @jsmith.projects.first.recipients.include?(@jsmith.mail)
end
def test_mail_notification_selected
@jsmith.mail_notification = false
@jsmith.notified_project_ids = [@jsmith.projects.first.id]
@jsmith.save
@jsmith.reload
assert @jsmith.projects.first.recipients.include?(@jsmith.mail)
end
def test_mail_notification_none
@jsmith.mail_notification = false
@jsmith.notified_project_ids = []
@jsmith.save
@jsmith.reload
assert !@jsmith.projects.first.recipients.include?(@jsmith.mail)
end
end end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment