##// END OF EJS Templates
Enable updating private_notes property on journal edit form (#22575)....
Jean-Philippe Lang -
r15238:7918285ac2e6
parent child
Show More
@@ -1,110 +1,113
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class JournalsController < ApplicationController
18 class JournalsController < ApplicationController
19 before_filter :find_journal, :only => [:edit, :update, :diff]
19 before_filter :find_journal, :only => [:edit, :update, :diff]
20 before_filter :find_issue, :only => [:new]
20 before_filter :find_issue, :only => [:new]
21 before_filter :find_optional_project, :only => [:index]
21 before_filter :find_optional_project, :only => [:index]
22 before_filter :authorize, :only => [:new, :edit, :update, :diff]
22 before_filter :authorize, :only => [:new, :edit, :update, :diff]
23 accept_rss_auth :index
23 accept_rss_auth :index
24 menu_item :issues
24 menu_item :issues
25
25
26 helper :issues
26 helper :issues
27 helper :custom_fields
27 helper :custom_fields
28 helper :queries
28 helper :queries
29 include QueriesHelper
29 include QueriesHelper
30 helper :sort
30 helper :sort
31 include SortHelper
31 include SortHelper
32
32
33 def index
33 def index
34 retrieve_query
34 retrieve_query
35 sort_init 'id', 'desc'
35 sort_init 'id', 'desc'
36 sort_update(@query.sortable_columns)
36 sort_update(@query.sortable_columns)
37 if @query.valid?
37 if @query.valid?
38 @journals = @query.journals(:order => "#{Journal.table_name}.created_on DESC",
38 @journals = @query.journals(:order => "#{Journal.table_name}.created_on DESC",
39 :limit => 25)
39 :limit => 25)
40 end
40 end
41 @title = (@project ? @project.name : Setting.app_title) + ": " + (@query.new_record? ? l(:label_changes_details) : @query.name)
41 @title = (@project ? @project.name : Setting.app_title) + ": " + (@query.new_record? ? l(:label_changes_details) : @query.name)
42 render :layout => false, :content_type => 'application/atom+xml'
42 render :layout => false, :content_type => 'application/atom+xml'
43 rescue ActiveRecord::RecordNotFound
43 rescue ActiveRecord::RecordNotFound
44 render_404
44 render_404
45 end
45 end
46
46
47 def diff
47 def diff
48 @issue = @journal.issue
48 @issue = @journal.issue
49 if params[:detail_id].present?
49 if params[:detail_id].present?
50 @detail = @journal.details.find_by_id(params[:detail_id])
50 @detail = @journal.details.find_by_id(params[:detail_id])
51 else
51 else
52 @detail = @journal.details.detect {|d| d.property == 'attr' && d.prop_key == 'description'}
52 @detail = @journal.details.detect {|d| d.property == 'attr' && d.prop_key == 'description'}
53 end
53 end
54 unless @issue && @detail
54 unless @issue && @detail
55 render_404
55 render_404
56 return false
56 return false
57 end
57 end
58 if @detail.property == 'cf'
58 if @detail.property == 'cf'
59 unless @detail.custom_field && @detail.custom_field.visible_by?(@issue.project, User.current)
59 unless @detail.custom_field && @detail.custom_field.visible_by?(@issue.project, User.current)
60 raise ::Unauthorized
60 raise ::Unauthorized
61 end
61 end
62 end
62 end
63 @diff = Redmine::Helpers::Diff.new(@detail.value, @detail.old_value)
63 @diff = Redmine::Helpers::Diff.new(@detail.value, @detail.old_value)
64 end
64 end
65
65
66 def new
66 def new
67 @journal = Journal.visible.find(params[:journal_id]) if params[:journal_id]
67 @journal = Journal.visible.find(params[:journal_id]) if params[:journal_id]
68 if @journal
68 if @journal
69 user = @journal.user
69 user = @journal.user
70 text = @journal.notes
70 text = @journal.notes
71 else
71 else
72 user = @issue.author
72 user = @issue.author
73 text = @issue.description
73 text = @issue.description
74 end
74 end
75 # Replaces pre blocks with [...]
75 # Replaces pre blocks with [...]
76 text = text.to_s.strip.gsub(%r{<pre>(.*?)</pre>}m, '[...]')
76 text = text.to_s.strip.gsub(%r{<pre>(.*?)</pre>}m, '[...]')
77 @content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> "
77 @content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> "
78 @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n"
78 @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n"
79 rescue ActiveRecord::RecordNotFound
79 rescue ActiveRecord::RecordNotFound
80 render_404
80 render_404
81 end
81 end
82
82
83 def edit
83 def edit
84 (render_403; return false) unless @journal.editable_by?(User.current)
84 (render_403; return false) unless @journal.editable_by?(User.current)
85 respond_to do |format|
85 respond_to do |format|
86 # TODO: implement non-JS journal update
86 # TODO: implement non-JS journal update
87 format.js
87 format.js
88 end
88 end
89 end
89 end
90
90
91 def update
91 def update
92 (render_403; return false) unless @journal.editable_by?(User.current)
92 (render_403; return false) unless @journal.editable_by?(User.current)
93 @journal.update_attributes(:notes => params[:notes]) if params[:notes]
93 @journal.notes = params[:notes] if params[:notes]
94 @journal.private_notes = params[:private_notes].present?
95 (render_403; return false) if @journal.private_notes_changed? && User.current.allowed_to?(:set_notes_private, @journal.issue.project) == false
96 @journal.save if @journal.changed?
94 @journal.destroy if @journal.details.empty? && @journal.notes.blank?
97 @journal.destroy if @journal.details.empty? && @journal.notes.blank?
95 call_hook(:controller_journals_edit_post, { :journal => @journal, :params => params})
98 call_hook(:controller_journals_edit_post, { :journal => @journal, :params => params})
96 respond_to do |format|
99 respond_to do |format|
97 format.html { redirect_to issue_path(@journal.journalized) }
100 format.html { redirect_to issue_path(@journal.journalized) }
98 format.js
101 format.js
99 end
102 end
100 end
103 end
101
104
102 private
105 private
103
106
104 def find_journal
107 def find_journal
105 @journal = Journal.visible.find(params[:id])
108 @journal = Journal.visible.find(params[:id])
106 @project = @journal.journalized.project
109 @project = @journal.journalized.project
107 rescue ActiveRecord::RecordNotFound
110 rescue ActiveRecord::RecordNotFound
108 render_404
111 render_404
109 end
112 end
110 end
113 end
@@ -1,61 +1,67
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2016 Jean-Philippe Lang
4 # Copyright (C) 2006-2016 Jean-Philippe Lang
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
9 # of the License, or (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
19
20 module JournalsHelper
20 module JournalsHelper
21
21
22 # Returns the attachments of a journal that are displayed as thumbnails
22 # Returns the attachments of a journal that are displayed as thumbnails
23 def journal_thumbnail_attachments(journal)
23 def journal_thumbnail_attachments(journal)
24 ids = journal.details.select {|d| d.property == 'attachment' && d.value.present?}.map(&:prop_key)
24 ids = journal.details.select {|d| d.property == 'attachment' && d.value.present?}.map(&:prop_key)
25 ids.any? ? Attachment.where(:id => ids).select(&:thumbnailable?) : []
25 ids.any? ? Attachment.where(:id => ids).select(&:thumbnailable?) : []
26 end
26 end
27
27
28 def render_notes(issue, journal, options={})
28 def render_notes(issue, journal, options={})
29 content = ''
29 content = ''
30 editable = User.current.logged? && (User.current.allowed_to?(:edit_issue_notes, issue.project) || (journal.user == User.current && User.current.allowed_to?(:edit_own_issue_notes, issue.project)))
30 editable = User.current.logged? && (User.current.allowed_to?(:edit_issue_notes, issue.project) || (journal.user == User.current && User.current.allowed_to?(:edit_own_issue_notes, issue.project)))
31 links = []
31 links = []
32 if !journal.notes.blank?
32 if !journal.notes.blank?
33 links << link_to(l(:button_quote),
33 links << link_to(l(:button_quote),
34 quoted_issue_path(issue, :journal_id => journal),
34 quoted_issue_path(issue, :journal_id => journal),
35 :remote => true,
35 :remote => true,
36 :method => 'post',
36 :method => 'post',
37 :title => l(:button_quote),
37 :title => l(:button_quote),
38 :class => 'icon-only icon-comment'
38 :class => 'icon-only icon-comment'
39 ) if options[:reply_links]
39 ) if options[:reply_links]
40 links << link_to(l(:button_edit),
40 links << link_to(l(:button_edit),
41 edit_journal_path(journal),
41 edit_journal_path(journal),
42 :remote => true,
42 :remote => true,
43 :method => 'get',
43 :method => 'get',
44 :title => l(:button_edit),
44 :title => l(:button_edit),
45 :class => 'icon-only icon-edit'
45 :class => 'icon-only icon-edit'
46 ) if editable
46 ) if editable
47 links << link_to(l(:button_delete),
47 links << link_to(l(:button_delete),
48 journal_path(journal, :notes => ""),
48 journal_path(journal, :notes => ""),
49 :remote => true,
49 :remote => true,
50 :method => 'put', :data => {:confirm => l(:text_are_you_sure)},
50 :method => 'put', :data => {:confirm => l(:text_are_you_sure)},
51 :title => l(:button_delete),
51 :title => l(:button_delete),
52 :class => 'icon-only icon-del'
52 :class => 'icon-only icon-del'
53 ) if editable
53 ) if editable
54 end
54 end
55 content << content_tag('div', links.join(' ').html_safe, :class => 'contextual') unless links.empty?
55 content << content_tag('div', links.join(' ').html_safe, :class => 'contextual') unless links.empty?
56 content << textilizable(journal, :notes)
56 content << textilizable(journal, :notes)
57 css_classes = "wiki"
57 css_classes = "wiki"
58 css_classes << " editable" if editable
58 css_classes << " editable" if editable
59 content_tag('div', content.html_safe, :id => "journal-#{journal.id}-notes", :class => css_classes)
59 content_tag('div', content.html_safe, :id => "journal-#{journal.id}-notes", :class => css_classes)
60 end
60 end
61
62 def render_private_notes(journal)
63 content = journal.private_notes? ? l(:field_is_private) : ''
64 css_classes = journal.private_notes? ? 'private' : ''
65 content_tag('span', content.html_safe, :id => "journal-#{journal.id}-private_notes", :class => css_classes)
66 end
61 end
67 end
@@ -1,30 +1,30
1 <% reply_links = issue.notes_addable? -%>
1 <% reply_links = issue.notes_addable? -%>
2 <% for journal in journals %>
2 <% for journal in journals %>
3 <div id="change-<%= journal.id %>" class="<%= journal.css_classes %>">
3 <div id="change-<%= journal.id %>" class="<%= journal.css_classes %>">
4 <div id="note-<%= journal.indice %>">
4 <div id="note-<%= journal.indice %>">
5 <h4><a href="#note-<%= journal.indice %>" class="journal-link">#<%= journal.indice %></a>
5 <h4><a href="#note-<%= journal.indice %>" class="journal-link">#<%= journal.indice %></a>
6 <%= avatar(journal.user, :size => "24") %>
6 <%= avatar(journal.user, :size => "24") %>
7 <%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %>
7 <%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %>
8 <%= content_tag('span', l(:field_is_private), :class => 'private') if journal.private_notes? %></h4>
8 <%= render_private_notes(journal) %></h4>
9
9
10 <% if journal.details.any? %>
10 <% if journal.details.any? %>
11 <ul class="details">
11 <ul class="details">
12 <% details_to_strings(journal.visible_details).each do |string| %>
12 <% details_to_strings(journal.visible_details).each do |string| %>
13 <li><%= string %></li>
13 <li><%= string %></li>
14 <% end %>
14 <% end %>
15 </ul>
15 </ul>
16 <% if Setting.thumbnails_enabled? && (thumbnail_attachments = journal_thumbnail_attachments(journal)).any? %>
16 <% if Setting.thumbnails_enabled? && (thumbnail_attachments = journal_thumbnail_attachments(journal)).any? %>
17 <div class="thumbnails">
17 <div class="thumbnails">
18 <% thumbnail_attachments.each do |attachment| %>
18 <% thumbnail_attachments.each do |attachment| %>
19 <div><%= thumbnail_tag(attachment) %></div>
19 <div><%= thumbnail_tag(attachment) %></div>
20 <% end %>
20 <% end %>
21 </div>
21 </div>
22 <% end %>
22 <% end %>
23 <% end %>
23 <% end %>
24 <%= render_notes(issue, journal, :reply_links => reply_links) unless journal.notes.blank? %>
24 <%= render_notes(issue, journal, :reply_links => reply_links) unless journal.notes.blank? %>
25 </div>
25 </div>
26 </div>
26 </div>
27 <%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %>
27 <%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %>
28 <% end %>
28 <% end %>
29
29
30 <% heads_for_wiki_formatter if User.current.allowed_to?(:edit_issue_notes, issue.project) || User.current.allowed_to?(:edit_own_issue_notes, issue.project) %>
30 <% heads_for_wiki_formatter if User.current.allowed_to?(:edit_issue_notes, issue.project) || User.current.allowed_to?(:edit_own_issue_notes, issue.project) %>
@@ -1,19 +1,22
1 <%= form_tag(journal_path(@journal),
1 <%= form_tag(journal_path(@journal),
2 :remote => true,
2 :remote => true,
3 :method => 'put',
3 :method => 'put',
4 :id => "journal-#{@journal.id}-form") do %>
4 :id => "journal-#{@journal.id}-form") do %>
5 <%= label_tag "notes", l(:description_notes), :class => "hidden-for-sighted" %>
5 <%= label_tag "notes", l(:description_notes), :class => "hidden-for-sighted" %>
6 <%= text_area_tag :notes, @journal.notes,
6 <%= text_area_tag :notes, @journal.notes,
7 :id => "journal_#{@journal.id}_notes",
7 :id => "journal_#{@journal.id}_notes",
8 :class => 'wiki-edit',
8 :class => 'wiki-edit',
9 :rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %>
9 :rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %>
10 <% if @journal.issue.safe_attribute? 'private_notes' %>
11 <%= check_box_tag 'private_notes', '1', @journal.private_notes, :id => "journal_#{@journal.id}_private_notes" %> <label for="journal_<%= @journal.id %>_private_notes"><%= l(:field_private_notes) %></label>
12 <% end %>
10 <%= call_hook(:view_journals_notes_form_after_notes, { :journal => @journal}) %>
13 <%= call_hook(:view_journals_notes_form_after_notes, { :journal => @journal}) %>
11 <p><%= submit_tag l(:button_save) %>
14 <p><%= submit_tag l(:button_save) %>
12 <%= preview_link preview_edit_issue_path(:project_id => @project, :id => @journal.issue),
15 <%= preview_link preview_edit_issue_path(:project_id => @project, :id => @journal.issue),
13 "journal-#{@journal.id}-form",
16 "journal-#{@journal.id}-form",
14 "journal_#{@journal.id}_preview" %> |
17 "journal_#{@journal.id}_preview" %> |
15 <%= link_to l(:button_cancel), '#', :onclick => "$('#journal-#{@journal.id}-form').remove(); $('#journal-#{@journal.id}-notes').show(); return false;" %></p>
18 <%= link_to l(:button_cancel), '#', :onclick => "$('#journal-#{@journal.id}-form').remove(); $('#journal-#{@journal.id}-notes').show(); return false;" %></p>
16
19
17 <div id="journal_<%= @journal.id %>_preview" class="wiki"></div>
20 <div id="journal_<%= @journal.id %>_preview" class="wiki"></div>
18 <% end %>
21 <% end %>
19 <%= wikitoolbar_for "journal_#{@journal.id}_notes" %>
22 <%= wikitoolbar_for "journal_#{@journal.id}_notes" %>
@@ -1,9 +1,11
1 <% if @journal.frozen? %>
1 <% if @journal.frozen? %>
2 $("#change-<%= @journal.id %>").remove();
2 $("#change-<%= @journal.id %>").remove();
3 <% else %>
3 <% else %>
4 $("#change-<%= @journal.id %>").attr('class', '<%= @journal.css_classes %>');
4 $("#journal-<%= @journal.id %>-notes").replaceWith('<%= escape_javascript(render_notes(@journal.issue, @journal, :reply_links => authorize_for('issues', 'edit'))) %>');
5 $("#journal-<%= @journal.id %>-notes").replaceWith('<%= escape_javascript(render_notes(@journal.issue, @journal, :reply_links => authorize_for('issues', 'edit'))) %>');
6 $("#journal-<%= @journal.id %>-private_notes").replaceWith('<%= escape_javascript(render_private_notes(@journal)) %>');
5 $("#journal-<%= @journal.id %>-notes").show();
7 $("#journal-<%= @journal.id %>-notes").show();
6 $("#journal-<%= @journal.id %>-form").remove();
8 $("#journal-<%= @journal.id %>-form").remove();
7 <% end %>
9 <% end %>
8
10
9 <%= call_hook(:view_journals_update_js_bottom, { :journal => @journal }) %>
11 <%= call_hook(:view_journals_update_js_bottom, { :journal => @journal }) %>
@@ -1,221 +1,254
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class JournalsControllerTest < ActionController::TestCase
20 class JournalsControllerTest < ActionController::TestCase
21 fixtures :projects, :users, :members, :member_roles, :roles, :issues, :journals, :journal_details, :enabled_modules,
21 fixtures :projects, :users, :members, :member_roles, :roles, :issues, :journals, :journal_details, :enabled_modules,
22 :trackers, :issue_statuses, :enumerations, :custom_fields, :custom_values, :custom_fields_projects, :projects_trackers
22 :trackers, :issue_statuses, :enumerations, :custom_fields, :custom_values, :custom_fields_projects, :projects_trackers
23
23
24 def setup
24 def setup
25 User.current = nil
25 User.current = nil
26 end
26 end
27
27
28 def test_index
28 def test_index
29 get :index, :project_id => 1
29 get :index, :project_id => 1
30 assert_response :success
30 assert_response :success
31 assert_not_nil assigns(:journals)
31 assert_not_nil assigns(:journals)
32 assert_equal 'application/atom+xml', @response.content_type
32 assert_equal 'application/atom+xml', @response.content_type
33 end
33 end
34
34
35 def test_index_with_invalid_query_id
35 def test_index_with_invalid_query_id
36 get :index, :project_id => 1, :query_id => 999
36 get :index, :project_id => 1, :query_id => 999
37 assert_response 404
37 assert_response 404
38 end
38 end
39
39
40 def test_index_should_return_privates_notes_with_permission_only
40 def test_index_should_return_privates_notes_with_permission_only
41 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Privates notes', :private_notes => true, :user_id => 1)
41 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Privates notes', :private_notes => true, :user_id => 1)
42 @request.session[:user_id] = 2
42 @request.session[:user_id] = 2
43
43
44 get :index, :project_id => 1
44 get :index, :project_id => 1
45 assert_response :success
45 assert_response :success
46 assert_include journal, assigns(:journals)
46 assert_include journal, assigns(:journals)
47
47
48 Role.find(1).remove_permission! :view_private_notes
48 Role.find(1).remove_permission! :view_private_notes
49 get :index, :project_id => 1
49 get :index, :project_id => 1
50 assert_response :success
50 assert_response :success
51 assert_not_include journal, assigns(:journals)
51 assert_not_include journal, assigns(:journals)
52 end
52 end
53
53
54 def test_index_should_show_visible_custom_fields_only
54 def test_index_should_show_visible_custom_fields_only
55 Issue.destroy_all
55 Issue.destroy_all
56 field_attributes = {:field_format => 'string', :is_for_all => true, :is_filter => true, :trackers => Tracker.all}
56 field_attributes = {:field_format => 'string', :is_for_all => true, :is_filter => true, :trackers => Tracker.all}
57 @fields = []
57 @fields = []
58 @fields << (@field1 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 1', :visible => true)))
58 @fields << (@field1 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 1', :visible => true)))
59 @fields << (@field2 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 2', :visible => false, :role_ids => [1, 2])))
59 @fields << (@field2 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 2', :visible => false, :role_ids => [1, 2])))
60 @fields << (@field3 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 3', :visible => false, :role_ids => [1, 3])))
60 @fields << (@field3 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 3', :visible => false, :role_ids => [1, 3])))
61 @issue = Issue.generate!(
61 @issue = Issue.generate!(
62 :author_id => 1,
62 :author_id => 1,
63 :project_id => 1,
63 :project_id => 1,
64 :tracker_id => 1,
64 :tracker_id => 1,
65 :custom_field_values => {@field1.id => 'Value0', @field2.id => 'Value1', @field3.id => 'Value2'}
65 :custom_field_values => {@field1.id => 'Value0', @field2.id => 'Value1', @field3.id => 'Value2'}
66 )
66 )
67 @issue.init_journal(User.find(1))
67 @issue.init_journal(User.find(1))
68 @issue.update_attribute :custom_field_values, {@field1.id => 'NewValue0', @field2.id => 'NewValue1', @field3.id => 'NewValue2'}
68 @issue.update_attribute :custom_field_values, {@field1.id => 'NewValue0', @field2.id => 'NewValue1', @field3.id => 'NewValue2'}
69
69
70
70
71 user_with_role_on_other_project = User.generate!
71 user_with_role_on_other_project = User.generate!
72 User.add_to_project(user_with_role_on_other_project, Project.find(2), Role.find(3))
72 User.add_to_project(user_with_role_on_other_project, Project.find(2), Role.find(3))
73 users_to_test = {
73 users_to_test = {
74 User.find(1) => [@field1, @field2, @field3],
74 User.find(1) => [@field1, @field2, @field3],
75 User.find(3) => [@field1, @field2],
75 User.find(3) => [@field1, @field2],
76 user_with_role_on_other_project => [@field1], # should see field1 only on Project 1
76 user_with_role_on_other_project => [@field1], # should see field1 only on Project 1
77 User.generate! => [@field1],
77 User.generate! => [@field1],
78 User.anonymous => [@field1]
78 User.anonymous => [@field1]
79 }
79 }
80
80
81 users_to_test.each do |user, visible_fields|
81 users_to_test.each do |user, visible_fields|
82 get :index, :format => 'atom', :key => user.rss_key
82 get :index, :format => 'atom', :key => user.rss_key
83 @fields.each_with_index do |field, i|
83 @fields.each_with_index do |field, i|
84 if visible_fields.include?(field)
84 if visible_fields.include?(field)
85 assert_select "content[type=html]", { :text => /NewValue#{i}/, :count => 1 }, "User #{user.id} was not able to view #{field.name} in API"
85 assert_select "content[type=html]", { :text => /NewValue#{i}/, :count => 1 }, "User #{user.id} was not able to view #{field.name} in API"
86 else
86 else
87 assert_select "content[type=html]", { :text => /NewValue#{i}/, :count => 0 }, "User #{user.id} was able to view #{field.name} in API"
87 assert_select "content[type=html]", { :text => /NewValue#{i}/, :count => 0 }, "User #{user.id} was able to view #{field.name} in API"
88 end
88 end
89 end
89 end
90 end
90 end
91
91
92 end
92 end
93
93
94 def test_diff_for_description_change
94 def test_diff_for_description_change
95 get :diff, :id => 3, :detail_id => 4
95 get :diff, :id => 3, :detail_id => 4
96 assert_response :success
96 assert_response :success
97 assert_template 'diff'
97 assert_template 'diff'
98
98
99 assert_select 'span.diff_out', :text => /removed/
99 assert_select 'span.diff_out', :text => /removed/
100 assert_select 'span.diff_in', :text => /added/
100 assert_select 'span.diff_in', :text => /added/
101 end
101 end
102
102
103 def test_diff_for_custom_field
103 def test_diff_for_custom_field
104 field = IssueCustomField.create!(:name => "Long field", :field_format => 'text')
104 field = IssueCustomField.create!(:name => "Long field", :field_format => 'text')
105 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Notes', :user_id => 1)
105 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Notes', :user_id => 1)
106 detail = JournalDetail.create!(:journal => journal, :property => 'cf', :prop_key => field.id,
106 detail = JournalDetail.create!(:journal => journal, :property => 'cf', :prop_key => field.id,
107 :old_value => 'Foo', :value => 'Bar')
107 :old_value => 'Foo', :value => 'Bar')
108
108
109 get :diff, :id => journal.id, :detail_id => detail.id
109 get :diff, :id => journal.id, :detail_id => detail.id
110 assert_response :success
110 assert_response :success
111 assert_template 'diff'
111 assert_template 'diff'
112
112
113 assert_select 'span.diff_out', :text => /Foo/
113 assert_select 'span.diff_out', :text => /Foo/
114 assert_select 'span.diff_in', :text => /Bar/
114 assert_select 'span.diff_in', :text => /Bar/
115 end
115 end
116
116
117 def test_diff_for_custom_field_should_be_denied_if_custom_field_is_not_visible
117 def test_diff_for_custom_field_should_be_denied_if_custom_field_is_not_visible
118 field = IssueCustomField.create!(:name => "Long field", :field_format => 'text', :visible => false, :role_ids => [1])
118 field = IssueCustomField.create!(:name => "Long field", :field_format => 'text', :visible => false, :role_ids => [1])
119 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Notes', :user_id => 1)
119 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Notes', :user_id => 1)
120 detail = JournalDetail.create!(:journal => journal, :property => 'cf', :prop_key => field.id,
120 detail = JournalDetail.create!(:journal => journal, :property => 'cf', :prop_key => field.id,
121 :old_value => 'Foo', :value => 'Bar')
121 :old_value => 'Foo', :value => 'Bar')
122
122
123 get :diff, :id => journal.id, :detail_id => detail.id
123 get :diff, :id => journal.id, :detail_id => detail.id
124 assert_response 302
124 assert_response 302
125 end
125 end
126
126
127 def test_diff_should_default_to_description_diff
127 def test_diff_should_default_to_description_diff
128 get :diff, :id => 3
128 get :diff, :id => 3
129 assert_response :success
129 assert_response :success
130 assert_template 'diff'
130 assert_template 'diff'
131
131
132 assert_select 'span.diff_out', :text => /removed/
132 assert_select 'span.diff_out', :text => /removed/
133 assert_select 'span.diff_in', :text => /added/
133 assert_select 'span.diff_in', :text => /added/
134 end
134 end
135
135
136 def test_reply_to_issue
136 def test_reply_to_issue
137 @request.session[:user_id] = 2
137 @request.session[:user_id] = 2
138 xhr :get, :new, :id => 6
138 xhr :get, :new, :id => 6
139 assert_response :success
139 assert_response :success
140 assert_template 'new'
140 assert_template 'new'
141 assert_equal 'text/javascript', response.content_type
141 assert_equal 'text/javascript', response.content_type
142 assert_include '> This is an issue', response.body
142 assert_include '> This is an issue', response.body
143 end
143 end
144
144
145 def test_reply_to_issue_without_permission
145 def test_reply_to_issue_without_permission
146 @request.session[:user_id] = 7
146 @request.session[:user_id] = 7
147 xhr :get, :new, :id => 6
147 xhr :get, :new, :id => 6
148 assert_response 403
148 assert_response 403
149 end
149 end
150
150
151 def test_reply_to_note
151 def test_reply_to_note
152 @request.session[:user_id] = 2
152 @request.session[:user_id] = 2
153 xhr :get, :new, :id => 6, :journal_id => 4
153 xhr :get, :new, :id => 6, :journal_id => 4
154 assert_response :success
154 assert_response :success
155 assert_template 'new'
155 assert_template 'new'
156 assert_equal 'text/javascript', response.content_type
156 assert_equal 'text/javascript', response.content_type
157 assert_include '> A comment with a private version', response.body
157 assert_include '> A comment with a private version', response.body
158 end
158 end
159
159
160 def test_reply_to_private_note_should_fail_without_permission
160 def test_reply_to_private_note_should_fail_without_permission
161 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Privates notes', :private_notes => true)
161 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Privates notes', :private_notes => true)
162 @request.session[:user_id] = 2
162 @request.session[:user_id] = 2
163
163
164 xhr :get, :new, :id => 2, :journal_id => journal.id
164 xhr :get, :new, :id => 2, :journal_id => journal.id
165 assert_response :success
165 assert_response :success
166 assert_template 'new'
166 assert_template 'new'
167 assert_equal 'text/javascript', response.content_type
167 assert_equal 'text/javascript', response.content_type
168 assert_include '> Privates notes', response.body
168 assert_include '> Privates notes', response.body
169
169
170 Role.find(1).remove_permission! :view_private_notes
170 Role.find(1).remove_permission! :view_private_notes
171 xhr :get, :new, :id => 2, :journal_id => journal.id
171 xhr :get, :new, :id => 2, :journal_id => journal.id
172 assert_response 404
172 assert_response 404
173 end
173 end
174
174
175 def test_edit_xhr
175 def test_edit_xhr
176 @request.session[:user_id] = 1
176 @request.session[:user_id] = 1
177 xhr :get, :edit, :id => 2
177 xhr :get, :edit, :id => 2
178 assert_response :success
178 assert_response :success
179 assert_template 'edit'
179 assert_template 'edit'
180 assert_equal 'text/javascript', response.content_type
180 assert_equal 'text/javascript', response.content_type
181 assert_include 'textarea', response.body
181 assert_include 'textarea', response.body
182 end
182 end
183
183
184 def test_edit_private_note_should_fail_without_permission
184 def test_edit_private_note_should_fail_without_permission
185 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Privates notes', :private_notes => true)
185 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Privates notes', :private_notes => true)
186 @request.session[:user_id] = 2
186 @request.session[:user_id] = 2
187 Role.find(1).add_permission! :edit_issue_notes
187 Role.find(1).add_permission! :edit_issue_notes
188
188
189 xhr :get, :edit, :id => journal.id
189 xhr :get, :edit, :id => journal.id
190 assert_response :success
190 assert_response :success
191 assert_template 'edit'
191 assert_template 'edit'
192 assert_equal 'text/javascript', response.content_type
192 assert_equal 'text/javascript', response.content_type
193 assert_include 'textarea', response.body
193 assert_include 'textarea', response.body
194
194
195 Role.find(1).remove_permission! :view_private_notes
195 Role.find(1).remove_permission! :view_private_notes
196 xhr :get, :edit, :id => journal.id
196 xhr :get, :edit, :id => journal.id
197 assert_response 404
197 assert_response 404
198 end
198 end
199
199
200 def test_update_xhr
200 def test_update_xhr
201 @request.session[:user_id] = 1
201 @request.session[:user_id] = 1
202 xhr :post, :update, :id => 2, :notes => 'Updated notes'
202 xhr :post, :update, :id => 2, :notes => 'Updated notes'
203 assert_response :success
203 assert_response :success
204 assert_template 'update'
204 assert_template 'update'
205 assert_equal 'text/javascript', response.content_type
205 assert_equal 'text/javascript', response.content_type
206 assert_equal 'Updated notes', Journal.find(2).notes
206 assert_equal 'Updated notes', Journal.find(2).notes
207 assert_include 'journal-2-notes', response.body
207 assert_include 'journal-2-notes', response.body
208 end
208 end
209
209
210 def test_update_xhr_with_private_notes_checked
211 @request.session[:user_id] = 1
212 xhr :post, :update, :id => 2, :private_notes => '1'
213 assert_response :success
214 assert_template 'update'
215 assert_equal 'text/javascript', response.content_type
216 assert_equal true, Journal.find(2).private_notes
217 assert_include 'change-2', response.body
218 assert_include 'journal-2-private_notes', response.body
219 end
220
221 def test_update_xhr_with_private_notes_unchecked
222 Journal.find(2).update_attributes(:private_notes => true)
223 @request.session[:user_id] = 1
224 xhr :post, :update, :id => 2
225 assert_response :success
226 assert_template 'update'
227 assert_equal 'text/javascript', response.content_type
228 assert_equal false, Journal.find(2).private_notes
229 assert_include 'change-2', response.body
230 assert_include 'journal-2-private_notes', response.body
231 end
232
233 def test_update_xhr_with_private_notes_changes_and_without_set_private_notes_permission
234 @request.session[:user_id] = 2
235 Role.find(1).add_permission! :edit_issue_notes
236 Role.find(1).add_permission! :view_private_notes
237 Role.find(1).remove_permission! :set_notes_private
238
239 xhr :post, :update, :id => 2, :private_notes => '1'
240 assert_response 403
241 end
242
210 def test_update_xhr_with_empty_notes_should_delete_the_journal
243 def test_update_xhr_with_empty_notes_should_delete_the_journal
211 @request.session[:user_id] = 1
244 @request.session[:user_id] = 1
212 assert_difference 'Journal.count', -1 do
245 assert_difference 'Journal.count', -1 do
213 xhr :post, :update, :id => 2, :notes => ''
246 xhr :post, :update, :id => 2, :notes => ''
214 assert_response :success
247 assert_response :success
215 assert_template 'update'
248 assert_template 'update'
216 assert_equal 'text/javascript', response.content_type
249 assert_equal 'text/javascript', response.content_type
217 end
250 end
218 assert_nil Journal.find_by_id(2)
251 assert_nil Journal.find_by_id(2)
219 assert_include 'change-2', response.body
252 assert_include 'change-2', response.body
220 end
253 end
221 end
254 end
General Comments 0
You need to be logged in to leave comments. Login now