diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2008-11-10 18:59:06 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2008-11-10 18:59:06 +0000 |
commit | 79c33bbc838fd837e516fd60569dbcf7917bd534 (patch) | |
tree | 20695e6f03f08925d6be3c96846668d979b4b3b3 /app | |
parent | f6b2be81b9cb09485a08e58fc73d9290fd544148 (diff) | |
download | redmine-79c33bbc838fd837e516fd60569dbcf7917bd534.tar.gz redmine-79c33bbc838fd837e516fd60569dbcf7917bd534.zip |
Maps repository users to Redmine users (#1383).
Users with same username or email are automatically mapped. Mapping can be manually adjusted in repository settings. Multiple usernames can be mapped to the same Redmine user.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2006 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/repositories_controller.rb | 14 | ||||
-rw-r--r-- | app/models/changeset.rb | 30 | ||||
-rw-r--r-- | app/models/repository.rb | 39 | ||||
-rw-r--r-- | app/models/user.rb | 1 | ||||
-rw-r--r-- | app/views/issues/_changesets.rhtml | 2 | ||||
-rw-r--r-- | app/views/issues/show.rfpdf | 2 | ||||
-rw-r--r-- | app/views/projects/settings/_repository.rhtml | 5 | ||||
-rw-r--r-- | app/views/repositories/_dir_list_content.rhtml | 4 | ||||
-rw-r--r-- | app/views/repositories/_revisions.rhtml | 2 | ||||
-rw-r--r-- | app/views/repositories/committers.rhtml | 29 | ||||
-rw-r--r-- | app/views/repositories/revision.rhtml | 2 |
11 files changed, 107 insertions, 23 deletions
diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 78576856d..17f836b7b 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 c4258c88b..dd38ce757 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 81e6647a2..0cae37d06 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 132896ad9..f468063ed 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 caa983cbf..15b75c61d 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 73d9d66b5..5926ba89d 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 dcfabbbf0..cdfb7feb4 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 20473a264..12ee44dbf 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 d8ca8007a..fb0131c82 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 000000000..6e3ba83b4 --- /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 123fccf26..c5bac720b 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 %> |