before_filter :find_project_by_project_id, :only => [:new, :create]
before_filter :find_repository, :only => [:edit, :update, :destroy, :committers]
before_filter :find_project_repository, :except => [:new, :create, :edit, :update, :destroy, :committers]
+ before_filter :find_changeset, :only => [:revision, :add_related_issue, :remove_related_issue]
before_filter :authorize
accept_rss_auth :revisions
end
def revision
- raise ChangesetNotFound if @rev.blank?
- @changeset = @repository.find_changeset_by_name(@rev)
- raise ChangesetNotFound unless @changeset
-
respond_to do |format|
format.html
format.js {render :layout => false}
end
- rescue ChangesetNotFound
- show_error_not_found
+ end
+
+ # Adds a related issue to a changeset
+ # POST /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues
+ def add_related_issue
+ @issue = @changeset.find_referenced_issue_by_id(params[:issue_id])
+ if @issue && (!@issue.visible? || @changeset.issues.include?(@issue))
+ @issue = nil
+ end
+
+ if @issue
+ @changeset.issues << @issue
+ respond_to do |format|
+ format.js {
+ render :update do |page|
+ page.replace_html "related-issues", :partial => "related_issues"
+ page.visual_effect :highlight, "related-issue-#{@issue.id}"
+ end
+ }
+ end
+ else
+ respond_to do |format|
+ format.js {
+ render :update do |page|
+ page.alert(l(:label_issue) + ' ' + l('activerecord.errors.messages.invalid'))
+ end
+ }
+ end
+ end
+ end
+
+ # Removes a related issue from a changeset
+ # DELETE /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues/:issue_id
+ def remove_related_issue
+ @issue = Issue.visible.find_by_id(params[:issue_id])
+ if @issue
+ @changeset.issues.delete(@issue)
+ end
+
+ respond_to do |format|
+ format.js {
+ render :update do |page|
+ page.remove "related-issue-#{@issue.id}"
+ end if @issue
+ }
+ end
end
def diff
show_error_not_found
end
+ def find_changeset
+ if @rev.present?
+ @changeset = @repository.find_changeset_by_name(@rev)
+ end
+ show_error_not_found unless @changeset
+ end
+
def show_error_not_found
render_error :message => l(:error_scm_not_found), :status => 404
end
:from_revision => change[:from_revision])
end
- private
-
# Finds an issue that can be referenced by the commit message
def find_referenced_issue_by_id(id)
return nil if id.blank?
issue
end
+ private
+
def fix_issue(issue)
status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i)
if status.nil?
--- /dev/null
+<% manage_allowed = User.current.allowed_to?(:manage_related_issues, @repository.project) %>
+
+<div id="related-issues">
+<% if manage_allowed %>
+ <div class="contextual">
+ <%= toggle_link l(:button_add), 'new-relation-form', {:focus => 'issue_id'} %>
+ </div>
+<% end %>
+
+<h3><%= l(:label_related_issues) %></h3>
+<ul>
+<% @changeset.issues.visible.each do |issue| %>
+ <li id="<%= "related-issue-#{issue.id}" %>"><%= link_to_issue issue %>
+ <%= link_to_remote(image_tag('link_break.png'),
+ {:url => {:controller => 'repositories', :action => 'remove_related_issue', :id => @project, :repository_id => @repository.identifier_param, :rev => @changeset.identifier, :issue_id => issue},
+ :method => :delete,
+ }, :title => l(:label_relation_delete)) if manage_allowed %>
+
+ </li>
+<% end %>
+</ul>
+
+<% if manage_allowed %>
+ <% remote_form_for(:issue, @issue,
+ :url => {:controller => 'repositories', :action => 'add_related_issue', :id => @project, :repository_id => @repository.identifier_param, :rev => @changeset.identifier},
+ :method => :post,
+ :complete => "Form.Element.focus('issue_id');",
+ :html => {:id => 'new-relation-form', :style => (@issue ? '' : 'display: none;')}) do |f| %>
+ <%= l(:label_issue) %> #<%= text_field_tag 'issue_id', '', :size => 10 %>
+ <%= submit_tag l(:button_add) %>
+ <%= toggle_link l(:button_cancel), 'new-relation-form'%>
+ <% end %>
+<% end %>
+</div>
<%= textilizable @changeset.comments %>
-<% if @changeset.issues.visible.any? %>
-<h3><%= l(:label_related_issues) %></h3>
-<ul>
-<% @changeset.issues.visible.each do |issue| %>
- <li><%= link_to_issue issue %></li>
-<% end %>
-</ul>
+<% if @changeset.issues.visible.any? || User.current.allowed_to?(:manage_related_issues, @repository.project) %>
+ <%= render :partial => 'related_issues' %>
<% end %>
<% if User.current.allowed_to?(:browse_repository, @project) %>
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
description_date_range_interval: Изберете диапазон чрез задаване на начална и крайна дати
description_date_from: Въведете начална дата
description_date_to: Въведете крайна дата
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
permission_delete_own_messages: Delete own messages
permission_export_wiki_pages: Export wiki pages
permission_manage_subtasks: Manage subtasks
+ permission_manage_related_issues: Manage related issues
project_module_issue_tracking: Issue tracking
project_module_time_tracking: Time tracking
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
permission_export_wiki_pages: Exporter les pages
permission_manage_project_activities: Gérer les activités
permission_manage_subtasks: Gérer les sous-tâches
+ permission_manage_related_issues: Gérer les demandes associées
project_module_issue_tracking: Suivi des demandes
project_module_time_tracking: Suivi du temps passé
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
+ permission_manage_related_issues: Manage related issues
:action => 'revisions'
repository_views.connect 'projects/:id/repository/:repository_id/revisions/:rev',
:action => 'revision'
+ repository_views.connect 'projects/:id/repository/:repository_id/revisions/:rev/issues',
+ :action => 'add_related_issue', :conditions => {:method => :post}
+ repository_views.connect 'projects/:id/repository/:repository_id/revisions/:rev/issues/:issue_id',
+ :action => 'remove_related_issue', :conditions => {:method => :delete}
repository_views.connect 'projects/:id/repository/:repository_id/revisions/:rev/diff',
:action => 'diff'
repository_views.connect 'projects/:id/repository/:repository_id/revisions/:rev/diff.:format',
:action => 'revisions'
repository_views.connect 'projects/:id/repository/revisions/:rev',
:action => 'revision'
+ repository_views.connect 'projects/:id/repository/revisions/:rev/issues',
+ :action => 'add_related_issue', :conditions => {:method => :post}
+ repository_views.connect 'projects/:id/repository/revisions/:rev/issues/:issue_id',
+ :action => 'remove_related_issue', :conditions => {:method => :delete}
repository_views.connect 'projects/:id/repository/revisions/:rev/diff',
:action => 'diff'
repository_views.connect 'projects/:id/repository/revisions/:rev/diff.:format',
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, {}
+ map.permission :manage_related_issues, {:repositories => [:add_related_issue, :remove_related_issue]}
end
map.project_module :boards do |map|
:manage_files,
:browse_repository,
:view_changesets,
- :commit_access]
+ :commit_access,
+ :manage_related_issues]
reporter = Role.create! :name => l(:default_role_reporter),
:position => 3,
#tracker_project_ids ul { margin: 0; padding-left: 1em; }
#tracker_project_ids li { list-style-type:none; }
+#related-issues li img {vertical-align:middle;}
+
ul.properties {padding:0; font-size: 0.9em; color: #777;}
ul.properties li {list-style-type:none;}
ul.properties li span {font-style:italic;}
- :browse_repository
- :manage_repository
- :view_changesets
+ - :manage_related_issues
- :manage_project_activities
position: 1
}
end
+ def test_add_related_issue
+ @request.session[:user_id] = 2
+ assert_difference 'Changeset.find(103).issues.size' do
+ post :add_related_issue, :id => 1, :rev => 4, :issue_id => 2
+ assert_response :success
+ end
+ assert_select_rjs :replace_html, 'related-issues'
+ assert_equal [2], Changeset.find(103).issue_ids
+ end
+
+ def test_add_related_issue_with_invalid_issue_id
+ @request.session[:user_id] = 2
+ assert_no_difference 'Changeset.find(103).issues.size' do
+ post :add_related_issue, :id => 1, :rev => 4, :issue_id => 9999
+ assert_response :success
+ end
+ assert_include 'alert("Issue is invalid")', @response.body
+ end
+
+ def test_remove_related_issue
+ Changeset.find(103).issues << Issue.find(1)
+ Changeset.find(103).issues << Issue.find(2)
+
+ @request.session[:user_id] = 2
+ assert_difference 'Changeset.find(103).issues.size', -1 do
+ delete :remove_related_issue, :id => 1, :rev => 4, :issue_id => 2
+ assert_response :success
+ end
+ assert_select_rjs :remove, 'related-issue-2'
+ assert_equal [1], Changeset.find(103).issue_ids
+ end
+
def test_graph_commits_per_month
get :graph, :id => 1, :graph => 'commits_per_month'
assert_response :success
)
end
+ def test_repositories_related_issues
+ assert_routing(
+ { :method => 'post',
+ :path => "/projects/redmine/repository/revisions/123/issues" },
+ { :controller => 'repositories', :action => 'add_related_issue', :id => 'redmine', :rev => '123' }
+ )
+ assert_routing(
+ { :method => 'delete',
+ :path => "/projects/redmine/repository/revisions/123/issues/25" },
+ { :controller => 'repositories', :action => 'remove_related_issue', :id => 'redmine', :rev => '123', :issue_id => '25' }
+ )
+ end
+
+ def test_repositories_related_issues_with_repository_id
+ assert_routing(
+ { :method => 'post',
+ :path => "/projects/redmine/repository/foo/revisions/123/issues" },
+ { :controller => 'repositories', :action => 'add_related_issue', :id => 'redmine', :repository_id => 'foo', :rev => '123' }
+ )
+ assert_routing(
+ { :method => 'delete',
+ :path => "/projects/redmine/repository/foo/revisions/123/issues/25" },
+ { :controller => 'repositories', :action => 'remove_related_issue', :id => 'redmine', :repository_id => 'foo', :rev => '123', :issue_id => '25' }
+ )
+ end
+
private
def repository_path_hash(arr)