diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 78576856d8703e279eeefca93714b03e99b0554c..17f836b7bbf46488f7d506eec54eff4776149414 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -44,6 +44,20 @@ class RepositoriesController < ApplicationController render(:update) {|page| page.replace_html "tab-content-repository", :partial => 'projects/settings/repository'} end + def committers + @committers = @repository.committers + @users = @project.users + additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id) + @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty? + @users.compact! + @users.sort! + if request.post? + @repository.committer_ids = params[:committers] + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'committers', :id => @project + end + end + def destroy @repository.destroy redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'repository' diff --git a/app/models/changeset.rb b/app/models/changeset.rb index c4258c88ba33bfaba1f93808c4d215145464dd6a..dd38ce757c231e95a20eee5fb8ed82b317114757 100644 --- a/app/models/changeset.rb +++ b/app/models/changeset.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2008 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 @@ -19,13 +19,13 @@ require 'iconv' class Changeset < ActiveRecord::Base belongs_to :repository + belongs_to :user has_many :changes, :dependent => :delete_all has_and_belongs_to_many :issues acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.revision}" + (o.comments.blank? ? '' : (': ' + o.comments))}, :description => :comments, :datetime => :committed_on, - :author => :committer, :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project_id, :rev => o.revision}} acts_as_searchable :columns => 'comments', @@ -57,6 +57,14 @@ class Changeset < ActiveRecord::Base repository.project end + def author + user || committer.to_s.split('<').first + end + + def before_create + self.user = repository.find_committer_user(committer) + end + def after_create scan_comment_for_issue_ids end @@ -96,12 +104,11 @@ class Changeset < ActiveRecord::Base issue.reload # don't change the status is the issue is closed next if issue.status.is_closed? - user = committer_user || User.anonymous csettext = "r#{self.revision}" if self.scmid && (! (csettext =~ /^r[0-9]+$/)) csettext = "commit:\"#{self.scmid}\"" end - journal = issue.init_journal(user, l(:text_status_changed_by_changeset, csettext)) + journal = issue.init_journal(user || User.anonymous, l(:text_status_changed_by_changeset, csettext)) issue.status = fix_status issue.done_ratio = done_ratio if done_ratio issue.save @@ -113,16 +120,6 @@ class Changeset < ActiveRecord::Base self.issues = referenced_issues.uniq end - - # Returns the Redmine User corresponding to the committer - def committer_user - if committer && committer.strip =~ /^([^<]+)(<(.*)>)?$/ - username, email = $1.strip, $3 - u = User.find_by_login(username) - u ||= User.find_by_mail(email) unless email.blank? - u - end - end # Returns the previous changeset def previous @@ -140,7 +137,8 @@ class Changeset < ActiveRecord::Base end private - + + def self.to_utf8(str) return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii encoding = Setting.commit_logs_encoding.to_s.strip diff --git a/app/models/repository.rb b/app/models/repository.rb index 81e6647a271c2fa288f087ec2910a682d5b83dde..0cae37d069ad6b8e7692472fafdb57550265e118 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -96,6 +96,45 @@ class Repository < ActiveRecord::Base self.changesets.each(&:scan_comment_for_issue_ids) end + # Returns an array of committers usernames and associated user_id + def committers + @committers ||= Changeset.connection.select_rows("SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}") + end + + # Maps committers username to a user ids + def committer_ids=(h) + if h.is_a?(Hash) + committers.each do |committer, user_id| + new_user_id = h[committer] + if new_user_id && (new_user_id.to_i != user_id.to_i) + new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil) + Changeset.update_all("user_id = #{ new_user_id.nil? ? 'NULL' : new_user_id }", ["repository_id = ? AND committer = ?", id, committer]) + end + end + @committers = nil + true + else + false + end + end + + # Returns the Redmine User corresponding to the given +committer+ + # It will return nil if the committer is not yet mapped and if no User + # with the same username or email was found + def find_committer_user(committer) + if committer + c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user) + if c && c.user + c.user + elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/ + username, email = $1.strip, $3 + u = User.find_by_login(username) + u ||= User.find_by_mail(email) unless email.blank? + u + end + end + end + # fetch new changesets for all repositories # can be called periodically by an external script # eg. ruby script/runner "Repository.fetch_changesets" diff --git a/app/models/user.rb b/app/models/user.rb index 132896ad9f5ca6b271a92efb01ef8175eae71efe..f468063ed6e86a9eefdc1a6f5b529867d8589395 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -37,6 +37,7 @@ class User < ActiveRecord::Base has_many :members, :dependent => :delete_all has_many :projects, :through => :memberships has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify + has_many :changesets, :dependent => :nullify has_one :preference, :dependent => :destroy, :class_name => 'UserPreference' has_one :rss_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='feeds'" belongs_to :auth_source diff --git a/app/views/issues/_changesets.rhtml b/app/views/issues/_changesets.rhtml index caa983cbf84d5efbfef14bbf3d5c65a901c16632..15b75c61de7d943d1d4ac74eb9b09526643854a3 100644 --- a/app/views/issues/_changesets.rhtml +++ b/app/views/issues/_changesets.rhtml @@ -2,7 +2,7 @@ <div class="changeset <%= cycle('odd', 'even') %>"> <p><%= link_to("#{l(:label_revision)} #{changeset.revision}", :controller => 'repositories', :action => 'revision', :id => @project, :rev => changeset.revision) %><br /> - <span class="author"><%= authoring(changeset.committed_on, changeset.committer) %></span></p> + <span class="author"><%= authoring(changeset.committed_on, changeset.author) %></span></p> <%= textilizable(changeset, :comments) %> </div> <% end %> diff --git a/app/views/issues/show.rfpdf b/app/views/issues/show.rfpdf index 73d9d66b565522b58fc62ec349fc002d58cfc209..5926ba89da85e193681b0cdad433c28a66894983 100644 --- a/app/views/issues/show.rfpdf +++ b/app/views/issues/show.rfpdf @@ -79,7 +79,7 @@ pdf.Ln for changeset in @issue.changesets pdf.SetFontStyle('B',8) - pdf.Cell(190,5, format_time(changeset.committed_on) + " - " + changeset.committer) + pdf.Cell(190,5, format_time(changeset.committed_on) + " - " + changeset.author) pdf.Ln unless changeset.comments.blank? pdf.SetFontStyle('',8) diff --git a/app/views/projects/settings/_repository.rhtml b/app/views/projects/settings/_repository.rhtml index dcfabbbf03e410b3561e52fee63d885670f61b27..cdfb7feb4c379a24cd87f3b9ca2176d17dbceb9e 100644 --- a/app/views/projects/settings/_repository.rhtml +++ b/app/views/projects/settings/_repository.rhtml @@ -11,10 +11,13 @@ </div> <div class="contextual"> +<% if @repository && !@repository.new_record? %> +<%= link_to(l(:label_user_plural), {:controller => 'repositories', :action => 'committers', :id => @project}, :class => 'icon icon-user') %> <%= link_to(l(:button_delete), {:controller => 'repositories', :action => 'destroy', :id => @project}, :confirm => l(:text_are_you_sure), :method => :post, - :class => 'icon icon-del') if @repository && !@repository.new_record? %> + :class => 'icon icon-del') %> +<% end %> </div> <%= submit_tag((@repository.nil? || @repository.new_record?) ? l(:button_create) : l(:button_save), :disabled => @repository.nil?) %> diff --git a/app/views/repositories/_dir_list_content.rhtml b/app/views/repositories/_dir_list_content.rhtml index 20473a26432055c5f790b2a2ba57b70f0aeec1d4..12ee44dbf0361453f6a800b160ee40c1cb04884d 100644 --- a/app/views/repositories/_dir_list_content.rhtml +++ b/app/views/repositories/_dir_list_content.rhtml @@ -15,10 +15,10 @@ :class => (entry.is_dir? ? 'icon icon-folder' : 'icon icon-file')%> </td> <td class="size"><%= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %></td> +<% changeset = @project.repository.changesets.find_by_revision(entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %> <td class="revision"><%= link_to(format_revision(entry.lastrev.name), :action => 'revision', :id => @project, :rev => entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %></td> <td class="age"><%= distance_of_time_in_words(entry.lastrev.time, Time.now) if entry.lastrev && entry.lastrev.time %></td> -<td class="author"><%=h(entry.lastrev.author.to_s.split('<').first) if entry.lastrev %></td> -<% changeset = @project.repository.changesets.find_by_revision(entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %> +<td class="author"><%= changeset.nil? ? h(entry.lastrev.author.to_s.split('<').first) : changeset.author if entry.lastrev %></td> <td class="comments"><%=h truncate(changeset.comments, 50) unless changeset.nil? %></td> </tr> <% end %> diff --git a/app/views/repositories/_revisions.rhtml b/app/views/repositories/_revisions.rhtml index d8ca8007af94b3fc471fe94b942acd1a75fdfcfa..fb0131c824f958e8063f7a431290b4d464996022 100644 --- a/app/views/repositories/_revisions.rhtml +++ b/app/views/repositories/_revisions.rhtml @@ -17,7 +17,7 @@ <td class="checkbox"><%= radio_button_tag('rev', changeset.revision, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('cbto-#{line_num+1}').checked=true;") if show_diff && (line_num < revisions.size) %></td> <td class="checkbox"><%= radio_button_tag('rev_to', changeset.revision, (line_num==2), :id => "cbto-#{line_num}", :onclick => "if ($('cb-#{line_num}').checked==true) {$('cb-#{line_num-1}').checked=true;}") if show_diff && (line_num > 1) %></td> <td class="committed_on"><%= format_time(changeset.committed_on) %></td> -<td class="author"><%=h changeset.committer.to_s.split('<').first %></td> +<td class="author"><%=h changeset.author %></td> <td class="comments"><%= textilizable(truncate_at_line_break(changeset.comments)) %></td> </tr> <% line_num += 1 %> diff --git a/app/views/repositories/committers.rhtml b/app/views/repositories/committers.rhtml new file mode 100644 index 0000000000000000000000000000000000000000..6e3ba83b42d75827a7a0db78e1c7bd136490bcff --- /dev/null +++ b/app/views/repositories/committers.rhtml @@ -0,0 +1,29 @@ +<h2><%= l(:label_repository) %></h2> + +<%= simple_format(l(:text_repository_usernames_mapping)) %> + +<% if @committers.empty? %> +<p class="nodata"><%= l(:label_no_data) %></p> +<% else %> + +<% form_tag({}) do %> +<table class="list"> +<thead> + <tr> + <th><%= l(:field_login) %></th> + <th><%= l(:label_user) %></th> + </tr> +</thead> +<tbody> +<% @committers.each do |committer, user_id| -%> + <tr class="<%= cycle 'odd', 'even' %>"> + <td><%=h committer %></td> + <td><%= select_tag "committers[#{committer}]", content_tag('option', "-- #{l :actionview_instancetag_blank_option} --", :value => '') + options_from_collection_for_select(@users, 'id', 'name', user_id.to_i) %></td> + </tr> +<% end -%> +</tbody> +</table> +<p><%= submit_tag(l(:button_update)) %></p> +<% end %> + +<% end %> \ No newline at end of file diff --git a/app/views/repositories/revision.rhtml b/app/views/repositories/revision.rhtml index 123fccf26160ce8decac197c247aacbd0b1bdad9..c5bac720b87ebeab0bf067ecbe74ce06b556e84c 100644 --- a/app/views/repositories/revision.rhtml +++ b/app/views/repositories/revision.rhtml @@ -22,7 +22,7 @@ <h2><%= l(:label_revision) %> <%= format_revision(@changeset.revision) %></h2> <p><% if @changeset.scmid %>ID: <%= @changeset.scmid %><br /><% end %> -<em><%= @changeset.committer.to_s.split('<').first %>, <%= format_time(@changeset.committed_on) %></em></p> +<span class="author"><%= authoring(@changeset.committed_on, @changeset.author) %></span></p> <%= textilizable @changeset.comments %> diff --git a/db/migrate/100_add_changesets_user_id.rb b/db/migrate/100_add_changesets_user_id.rb new file mode 100644 index 0000000000000000000000000000000000000000..9b25fd7bc867d211142bf87230b815c614c20b4e --- /dev/null +++ b/db/migrate/100_add_changesets_user_id.rb @@ -0,0 +1,9 @@ +class AddChangesetsUserId < ActiveRecord::Migration + def self.up + add_column :changesets, :user_id, :integer, :default => nil + end + + def self.down + remove_column :changesets, :user_id + end +end diff --git a/db/migrate/101_populate_changesets_user_id.rb b/db/migrate/101_populate_changesets_user_id.rb new file mode 100644 index 0000000000000000000000000000000000000000..dd493d17d09df1c8ea89d3c181713ebad6432bac --- /dev/null +++ b/db/migrate/101_populate_changesets_user_id.rb @@ -0,0 +1,18 @@ +class PopulateChangesetsUserId < ActiveRecord::Migration + def self.up + committers = Changeset.connection.select_values("SELECT DISTINCT committer FROM #{Changeset.table_name}") + committers.each do |committer| + next if committer.blank? + if committer.strip =~ /^([^<]+)(<(.*)>)?$/ + username, email = $1.strip, $3 + u = User.find_by_login(username) + u ||= User.find_by_mail(email) unless email.blank? + Changeset.update_all("user_id = #{u.id}", ["committer = ?", committer]) unless u.nil? + end + end + end + + def self.down + Changeset.update_all('user_id = NULL') + end +end diff --git a/lang/bg.yml b/lang/bg.yml index bc83098455c216aaaca1db7249eb5d4484a66730..000f0a97791cb00d92476c53f5bba3b9220bf024 100644 --- a/lang/bg.yml +++ b/lang/bg.yml @@ -689,3 +689,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/ca.yml b/lang/ca.yml index 79312829314128cb513ae7d3de6095f99e9272b9..5db547ac596ce10f455bcebc6a8caf238d04213c 100644 --- a/lang/ca.yml +++ b/lang/ca.yml @@ -690,3 +690,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/cs.yml b/lang/cs.yml index 7e49482c2d8b3b7625f5ff297e1cb90323ab0b28..09ed76ea971f6309a5b1d33ca684b6fd70ca5e90 100644 --- a/lang/cs.yml +++ b/lang/cs.yml @@ -694,3 +694,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/da.yml b/lang/da.yml index a5b8ddfb5b652082cd8f35adf4d389bd2690dc8c..b5081e9eec70b78305882b4e832d618f3e72fb7c 100644 --- a/lang/da.yml +++ b/lang/da.yml @@ -690,3 +690,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/de.yml b/lang/de.yml index 7d4b7959f6b9440616abcc5b32231018bfb368cc..3e59bcf9e9095c4ce11a0af422a1f32d0f7965c5 100644 --- a/lang/de.yml +++ b/lang/de.yml @@ -690,3 +690,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/en.yml b/lang/en.yml index a76c5d1a586ecbeb8719d771806e017d6cc2b21e..e9d7a1706c833f547bd4257fa71cb32ccd2e91c6 100644 --- a/lang/en.yml +++ b/lang/en.yml @@ -665,6 +665,7 @@ text_user_wrote: '%s wrote:' text_enumeration_destroy_question: '%d objects are assigned to this value.' text_enumeration_category_reassign_to: 'Reassign them to this value:' text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them." +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." default_role_manager: Manager default_role_developper: Developer diff --git a/lang/es.yml b/lang/es.yml index 74ca4119ad49f9c67d9b0f68e15b2b1ecb859f1d..c3b9de2b6aa69032810c2bd0c7ecde85a702409c 100644 --- a/lang/es.yml +++ b/lang/es.yml @@ -692,3 +692,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/fi.yml b/lang/fi.yml index 17423bf86ef0b483a1f7c1412be014d6a2230b1a..bdcefef9cd119c9a5a4e9c1a6947988b877d3bcc 100644 --- a/lang/fi.yml +++ b/lang/fi.yml @@ -689,3 +689,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/fr.yml b/lang/fr.yml index 556bb454800e8f03452ff5dd332151055579cf1c..ab34575b25909a6f669ecf5ebcd69373c65dcd73 100644 --- a/lang/fr.yml +++ b/lang/fr.yml @@ -665,6 +665,7 @@ text_user_wrote: '%s a écrit:' text_enumeration_destroy_question: 'Cette valeur est affectée à %d objets.' text_enumeration_category_reassign_to: 'Réaffecter les objets à cette valeur:' text_email_delivery_not_configured: "L'envoi de mail n'est pas configuré, les notifications sont désactivées.\nConfigurez votre serveur SMTP dans config/email.yml et redémarrez l'application pour les activer." +text_repository_usernames_mapping: "Vous pouvez sélectionner ou modifier l'utilisateur Redmine associé à chaque nom d'utilisateur figurant dans l'historique du dépôt.\nLes utilisateurs avec le même identifiant ou la même adresse mail seront automatiquement associés." default_role_manager: Manager default_role_developper: Développeur diff --git a/lang/he.yml b/lang/he.yml index 59474f6ce64af99bdd5cb84e51c690498a16ded5..13eab75c5bee8154ad51f3279c59da578ab46fde 100644 --- a/lang/he.yml +++ b/lang/he.yml @@ -689,3 +689,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/hu.yml b/lang/hu.yml index 8a508a1e673f4cf424487fa25780000dca845aca..1c4afdcd35d18db5827d4065e54c3978b031fb88 100644 --- a/lang/hu.yml +++ b/lang/hu.yml @@ -690,3 +690,4 @@ permission_edit_time_entries: IdÅ‘naplók szerkesztése permission_edit_own_issue_notes: Saját jegyzetek szerkesztése setting_gravatar_enabled: Felhasználói fényképek engedélyezése label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/it.yml b/lang/it.yml index e33e6b8a3f6692afece7eebd11b43a4197d1470d..c6ae84a912ab539013c2f4e3e8202d002dc863c3 100644 --- a/lang/it.yml +++ b/lang/it.yml @@ -689,3 +689,4 @@ permission_edit_time_entries: Modifica time logs permission_edit_own_issue_notes: Modifica proprie note setting_gravatar_enabled: Usa icone utente Gravatar label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/ja.yml b/lang/ja.yml index cd55ab896679debeaa7e877f1ccf5e628adc13d5..4092584d7009ddcff33b318f474aef4a76207874 100644 --- a/lang/ja.yml +++ b/lang/ja.yml @@ -690,3 +690,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/ko.yml b/lang/ko.yml index 8a1030da789b65cb492f6c185d775ab682cf0a4d..595acfa9ef2a60ad59869303c3b355bef84a9cae 100644 --- a/lang/ko.yml +++ b/lang/ko.yml @@ -689,3 +689,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/lt.yml b/lang/lt.yml index f9e5bea145d024029ca5fa7496d3fd86418bfa56..544cb14f972567ea5c1e1d63fe37c728ffc323bb 100644 --- a/lang/lt.yml +++ b/lang/lt.yml @@ -691,3 +691,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/nl.yml b/lang/nl.yml index 229fb8e77c82e479866542008cfc2734fa73825d..3434b14817a4429dcf395b6ff4a1ce59d3b9f874 100644 --- a/lang/nl.yml +++ b/lang/nl.yml @@ -691,3 +691,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/no.yml b/lang/no.yml index 5faa25fc10e13f6c8a579e07021c4758ec2afc25..ca056f809016e093f6cb1d316f13d23172e47976 100644 --- a/lang/no.yml +++ b/lang/no.yml @@ -690,3 +690,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/pl.yml b/lang/pl.yml index 246c147e4ddd51ee93c6ca5821b3e28d2aa096f8..df7d525dc714a4ff2d277df51bee9aedd37b1631 100644 --- a/lang/pl.yml +++ b/lang/pl.yml @@ -724,3 +724,4 @@ permission_edit_own_issue_notes: Edycja wÅ‚asnych notatek setting_gravatar_enabled: Używaj ikon użytkowników Gravatar label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/pt-br.yml b/lang/pt-br.yml index 3ead43b80a724f163390f0353d782732381d1ff6..4e34231af2c6f51f6c63b2a184347c8ee61ecf89 100644 --- a/lang/pt-br.yml +++ b/lang/pt-br.yml @@ -690,3 +690,4 @@ permission_edit_time_entries: Editar tempo gasto permission_edit_own_issue_notes: Editar próprias notas setting_gravatar_enabled: Usar Ãcones do Gravatar label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/pt.yml b/lang/pt.yml index 878eae1fcd30da5307d9d2f487c45e65c50eff2b..ce1e27a364969b688610c637f7ddc3a1afe401a5 100644 --- a/lang/pt.yml +++ b/lang/pt.yml @@ -691,3 +691,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/ro.yml b/lang/ro.yml index bde50a98df3c2ae38f02e3a49f2528c846b3ea00..8890f6e2db4bf449eb1bbfeb8f619ef8745aa5cb 100644 --- a/lang/ro.yml +++ b/lang/ro.yml @@ -689,3 +689,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/ru.yml b/lang/ru.yml index f7ca8fc073790fc73baac1238bbd27e5f51f72f1..363386dc9788e90ed405b72ca8e2734201b76017 100644 --- a/lang/ru.yml +++ b/lang/ru.yml @@ -722,3 +722,4 @@ text_user_mail_option: "Ð”Ð»Ñ Ð½ÐµÐ²Ñ‹Ð±Ñ€Ð°Ð½Ð½Ñ‹Ñ… проектов, Ð’Ñ‹ б text_user_wrote: '%s напиÑал(а):' text_wiki_destroy_confirmation: Ð’Ñ‹ уверены, что хотите удалить данную Wiki и вÑе ее Ñодержимое? text_workflow_edit: Выберите роль и трекер Ð´Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾ÑледовательноÑти ÑоÑтоÑний +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/sk.yml b/lang/sk.yml index 919f13d9aa50037732cde159bb70f9142ef37811..5c53eda2fdabd3967b72ef8334ad3e0ff42679eb 100644 --- a/lang/sk.yml +++ b/lang/sk.yml @@ -694,3 +694,4 @@ permission_edit_time_entries: Editácia Äasových záznamov permission_edit_own_issue_notes: Editácia vlastných poznámok úlohy setting_gravatar_enabled: Použitie uživateľských Gravatar ikon label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/sr.yml b/lang/sr.yml index 27466e14edc1a4986b8d117adbdb2c6429fc780b..54b1e70c6a3a6ba4421aa20b689e5ab7d7672777 100644 --- a/lang/sr.yml +++ b/lang/sr.yml @@ -690,3 +690,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/sv.yml b/lang/sv.yml index 29789c12433b3455682d73f60e7f8d406ff5d935..76b6e6c3869e0a67f6bd94a60d6a1f2cf53a2f1f 100644 --- a/lang/sv.yml +++ b/lang/sv.yml @@ -690,3 +690,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/th.yml b/lang/th.yml index 1bb60eacc6452cbb81fb40e6f973dc991dbda75e..fa471101f68aa6e3fd2fc6f3adb3c32c27a07025 100644 --- a/lang/th.yml +++ b/lang/th.yml @@ -692,3 +692,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/tr.yml b/lang/tr.yml index 439303a70aaa0c2b59dde3341aec949bcd5e6172..90d4d5f651546ff8722b54b03ac201b0790527bf 100644 --- a/lang/tr.yml +++ b/lang/tr.yml @@ -690,3 +690,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/uk.yml b/lang/uk.yml index 5f18b0e2298cc1ee8aea9c519bfd68ab55534088..a7f3f7347ee86c90e826fe9e95051533291e3554 100644 --- a/lang/uk.yml +++ b/lang/uk.yml @@ -691,3 +691,4 @@ permission_edit_time_entries: Edit time logs permission_edit_own_issue_notes: Edit own notes setting_gravatar_enabled: Use Gravatar user icons label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/vn.yml b/lang/vn.yml index 8ddc77e473165154dcbeff4d7a71502fa0827c02..81957a53cc802a690bb2c1a5e4cf124ee0617028 100644 --- a/lang/vn.yml +++ b/lang/vn.yml @@ -690,3 +690,4 @@ permission_save_queries: Save queries permission_edit_time_entries: Edit time logs permission_edit_own_time_entries: Edit own time logs label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/zh-tw.yml b/lang/zh-tw.yml index 2e4a5f02d1a35cd6be41dcaef336a34173302a00..40dc47b8b0d1d9860b182f7063b78fdaa0100a1b 100644 --- a/lang/zh-tw.yml +++ b/lang/zh-tw.yml @@ -691,3 +691,4 @@ enumeration_issue_priorities: é …ç›®å„ªå…ˆæ¬Š enumeration_doc_categories: 文件分類 enumeration_activities: 活動 (時間追蹤) label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lang/zh.yml b/lang/zh.yml index 00f95dcae15e1728752e1e25ed22e10518ea0768..10fd1ac01d9c15237ad2c1ca3fefd70300e96d25 100644 --- a/lang/zh.yml +++ b/lang/zh.yml @@ -691,3 +691,4 @@ enumeration_issue_priorities: 问题优先级 enumeration_doc_categories: 文档类别 enumeration_activities: 活动(时间跟踪) label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." diff --git a/lib/redmine.rb b/lib/redmine.rb index eeb12e00a48c6e8058f5f46fe429372028563550..b07d8e90cc87ee0bcb483ffd2c7ddd8eb4af3c88 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -88,7 +88,7 @@ Redmine::AccessControl.map do |map| end map.project_module :repository do |map| - map.permission :manage_repository, {:repositories => [:edit, :destroy]}, :require => :member + map.permission :manage_repository, {:repositories => [:edit, :committers, :destroy]}, :require => :member map.permission :browse_repository, :repositories => [:show, :browse, :entry, :annotate, :changes, :diff, :stats, :graph] map.permission :view_changesets, :repositories => [:show, :revisions, :revision] map.permission :commit_access, {} diff --git a/test/fixtures/changesets.yml b/test/fixtures/changesets.yml index 3b47eecd80590938f05883b71d8d10a8c62bcf83..cbc00eb83d9be00b5d03570cac3a77b2759d1cc7 100644 --- a/test/fixtures/changesets.yml +++ b/test/fixtures/changesets.yml @@ -7,6 +7,7 @@ changesets_001: comments: My very first commit repository_id: 10 committer: dlopper + user_id: 3 changesets_002: commit_date: 2007-04-12 committed_on: 2007-04-12 15:14:44 +02:00 @@ -15,6 +16,7 @@ changesets_002: comments: 'This commit fixes #1, #2 and references #1 & #3' repository_id: 10 committer: dlopper + user_id: 3 changesets_003: commit_date: 2007-04-12 committed_on: 2007-04-12 15:14:44 +02:00 @@ -25,6 +27,7 @@ changesets_003: IssueID 666 3 repository_id: 10 committer: dlopper + user_id: 3 changesets_004: commit_date: 2007-04-12 committed_on: 2007-04-12 15:14:44 +02:00 @@ -35,4 +38,5 @@ changesets_004: IssueID 4 2 repository_id: 10 committer: dlopper + user_id: 3 \ No newline at end of file diff --git a/test/fixtures/roles.yml b/test/fixtures/roles.yml index 78e0f0329074536ee9eb8f0ef845f55951425950..5bc6809d72f84f2d683f4c4144d8da1eae75f1bc 100644 --- a/test/fixtures/roles.yml +++ b/test/fixtures/roles.yml @@ -43,6 +43,7 @@ roles_001: - :view_files - :manage_files - :browse_repository + - :manage_repository - :view_changesets position: 1 diff --git a/test/functional/repositories_controller_test.rb b/test/functional/repositories_controller_test.rb index 2892f3bd19f9ea19ada5f7da44f2d4dfacd9737d..4bb9c3fa39f0222503a301c8dd979754ebf88dd3 100644 --- a/test/functional/repositories_controller_test.rb +++ b/test/functional/repositories_controller_test.rb @@ -61,4 +61,38 @@ class RepositoriesControllerTest < Test::Unit::TestCase assert_response :success assert_equal 'image/svg+xml', @response.content_type end + + def test_committers + @request.session[:user_id] = 2 + # add a commit with an unknown user + Changeset.create!(:repository => Project.find(1).repository, :committer => 'foo', :committed_on => Time.now, :revision => 100, :comments => 'Committed by foo.') + + get :committers, :id => 1 + assert_response :success + assert_template 'committers' + + assert_tag :td, :content => 'dlopper', + :sibling => { :tag => 'td', + :child => { :tag => 'select', :attributes => { :name => 'committers[dlopper]' }, + :child => { :tag => 'option', :content => 'Dave Lopper', + :attributes => { :value => '3', :selected => 'selected' }}}} + assert_tag :td, :content => 'foo', + :sibling => { :tag => 'td', + :child => { :tag => 'select', :attributes => { :name => 'committers[foo]' }}} + assert_no_tag :td, :content => 'foo', + :sibling => { :tag => 'td', + :descendant => { :tag => 'option', :attributes => { :selected => 'selected' }}} + end + + def test_map_committers + @request.session[:user_id] = 2 + # add a commit with an unknown user + c = Changeset.create!(:repository => Project.find(1).repository, :committer => 'foo', :committed_on => Time.now, :revision => 100, :comments => 'Committed by foo.') + + assert_no_difference "Changeset.count(:conditions => 'user_id = 3')" do + post :committers, :id => 1, :committers => { 'foo' => '2', 'dlopper' => '3'} + assert_redirected_to '/repositories/committers/ecookbook' + assert_equal User.find(2), c.reload.user + end + end end diff --git a/test/unit/repository_git_test.rb b/test/unit/repository_git_test.rb index da95d439f78d2d6286e5d15e696f65e86e390184..bc997b96c87d215f17bb41d8c17a519436af5787 100644 --- a/test/unit/repository_git_test.rb +++ b/test/unit/repository_git_test.rb @@ -40,6 +40,7 @@ class RepositoryGitTest < Test::Unit::TestCase commit = @repository.changesets.find(:first, :order => 'committed_on ASC') assert_equal "Initial import.\nThe repository contains 3 files.", commit.comments assert_equal "jsmith <jsmith@foo.bar>", commit.committer + assert_equal User.find_by_login('jsmith'), commit.user # TODO: add a commit with commit time <> author time to the test repository assert_equal "2007-12-14 09:22:52".to_time, commit.committed_on assert_equal "2007-12-14".to_date, commit.commit_date diff --git a/test/unit/repository_test.rb b/test/unit/repository_test.rb index 9ea9fdd45fa919df32d6d51ad932caa2a825d8e7..47230cf565300aaf878c0571caec1495d4698fb8 100644 --- a/test/unit/repository_test.rb +++ b/test/unit/repository_test.rb @@ -127,4 +127,26 @@ class RepositoryTest < Test::Unit::TestCase assert_equal ':pserver:login:password@host:/path/to/the/repository', repository.url assert_equal 'foo', repository.root_url end + + def test_manual_user_mapping + assert_no_difference "Changeset.count(:conditions => 'user_id <> 2')" do + c = Changeset.create!(:repository => @repository, :committer => 'foo', :committed_on => Time.now, :revision => 100, :comments => 'Committed by foo.') + assert_nil c.user + @repository.committer_ids = {'foo' => '2'} + assert_equal User.find(2), c.reload.user + # committer is now mapped + c = Changeset.create!(:repository => @repository, :committer => 'foo', :committed_on => Time.now, :revision => 101, :comments => 'Another commit by foo.') + assert_equal User.find(2), c.user + end + end + + def test_auto_user_mapping_by_username + c = Changeset.create!(:repository => @repository, :committer => 'jsmith', :committed_on => Time.now, :revision => 100, :comments => 'Committed by john.') + assert_equal User.find(2), c.user + end + + def test_auto_user_mapping_by_email + c = Changeset.create!(:repository => @repository, :committer => 'john <jsmith@somenet.foo>', :committed_on => Time.now, :revision => 100, :comments => 'Committed by john.') + assert_equal User.find(2), c.user + end end