Project

General

Profile

Feature #33820 » feature-33820-v2.diff

Mizuki ISHIKAWA, 2020-11-18 01:13

View differences:

app/controllers/auto_completes_controller.rb
42 42
    render :json => format_issues_json(issues)
43 43
  end
44 44

  
45
  def wiki_pages
46
    q = params[:q].to_s.strip
47
    wiki = Wiki.find_by(project: @project)
48
    scope = (@project && wiki ? wiki.pages : WikiPage.all).reorder(id: :desc)
49
    wiki_pages =
50
      if q.present?
51
        scope.where("LOWER(#{WikiPage.table_name}.title) LIKE LOWER(?)", "%#{q}%").limit(10).to_a
52
      else
53
        scope.limit(10).to_a
54
      end
55
    render :json => format_wiki_pages_json(wiki_pages)
56
  end
57

  
45 58
  private
46 59

  
47 60
  def find_project
......
61 74
      }
62 75
    end
63 76
  end
77

  
78
  def format_wiki_pages_json(wiki_pages)
79
    wiki_pages.map {|wiki_page|
80
      {
81
        'id' => wiki_page.id,
82
        'label' => wiki_page.title.to_s.truncate(255),
83
        'value' => wiki_page.title
84
      }
85
    }
86
  end
64 87
end
app/helpers/application_helper.rb
1743 1743

  
1744 1744
  def autocomplete_data_sources(project)
1745 1745
    {
1746
      issues: auto_complete_issues_path(:project_id => project, :q => '')
1746
      issues: auto_complete_issues_path(:project_id => project, :q => ''),
1747
      wiki_pages: auto_complete_wiki_pages_path(:project_id => project, :q => '')
1747 1748
    }
1748 1749
  end
1749 1750

  
config/routes.rb
46 46
  post 'boards/:board_id/topics/:id/edit', :to => 'messages#edit'
47 47
  post 'boards/:board_id/topics/:id/destroy', :to => 'messages#destroy'
48 48

  
49
  # Misc issue routes. TODO: move into resources
49
  # Auto complate routes
50 50
  match '/issues/auto_complete', :to => 'auto_completes#issues', :via => :get, :as => 'auto_complete_issues'
51
  match '/wiki_pages/auto_complete', :to => 'auto_completes#wiki_pages', :via => :get, :as => 'auto_complete_wiki_pages'
52

  
53
  # Misc issue routes. TODO: move into resources
51 54
  match '/issues/context_menu', :to => 'context_menus#issues', :as => 'issues_context_menu', :via => [:get, :post]
52 55
  match '/issues/changes', :to => 'journals#index', :as => 'issue_changes', :via => :get
53 56
  match '/issues/:id/quoted', :to => 'journals#new', :id => /\d+/, :via => :post, :as => 'quoted_issue'
lib/redmine.rb
162 162
  end
163 163

  
164 164
  map.project_module :wiki do |map|
165
    map.permission :view_wiki_pages, {:wiki => [:index, :show, :special, :date_index]}, :read => true
165
    map.permission :view_wiki_pages, {:wiki => [:index, :show, :special, :date_index], :auto_complete => [:wiki_pages]}, :read => true
166 166
    map.permission :view_wiki_edits, {:wiki => [:history, :diff, :annotate]}, :read => true
167 167
    map.permission :export_wiki_pages, {:wiki => [:export]}, :read => true
168 168
    map.permission :edit_wiki_pages, :wiki => [:new, :edit, :update, :preview, :add_attachment], :attachments => :upload
public/javascripts/application.js
1080 1080
    };
1081 1081

  
1082 1082
    const tribute = new Tribute({
1083
      trigger: '#',
1084
      values: function (text, cb) {
1085
        if (event.target.type === 'text' && $(element).attr('autocomplete') != 'off') {
1086
          $(element).attr('autocomplete', 'off');
1083
      collection: [
1084
        {
1085
          trigger: '#',
1086
          values: function (text, cb) {
1087
            if (event.target.type === 'text' && $(element).attr('autocomplete') != 'off') {
1088
              $(element).attr('autocomplete', 'off');
1089
            }
1090
            remoteSearch(getDataSource('issues') + text, function (issues) {
1091
              return cb(issues);
1092
            });
1093
          },
1094
          lookup: 'label',
1095
          fillAttr: 'label',
1096
          requireLeadingSpace: true,
1097
          selectTemplate: function (issue) {
1098
            return '#' + issue.original.id;
1099
          },
1100
          noMatchTemplate: function () {
1101
            return '<span style:"visibility: hidden;"></span>';
1102
          }
1103
        },
1104
        {
1105
          trigger: '[[',
1106
          values: function (text, cb) {
1107
            remoteSearch(getDataSource('wiki_pages') + text, function (wikiPages) {
1108
              return cb(wikiPages);
1109
            });
1110
          },
1111
          lookup: 'label',
1112
          fillAttr: 'label',
1113
          requireLeadingSpace: true,
1114
          selectTemplate: function (wikiPage) {
1115
            return '[[' + wikiPage.original.value + ']]';
1116
          },
1117
          noMatchTemplate: function () {
1118
            return '<span style:"visibility: hidden;"></span>';
1119
          }
1087 1120
        }
1088
        remoteSearch(getDataSource('issues') + text, function (issues) {
1089
          return cb(issues);
1090
        });
1091
      },
1092
      lookup: 'label',
1093
      fillAttr: 'label',
1094
      requireLeadingSpace: true,
1095
      selectTemplate: function (issue) {
1096
        return '#' + issue.original.id;
1097
      },
1098
      noMatchTemplate: function () {
1099
        return '<span style:"visibility: hidden;"></span>';
1100
      }
1121
      ]
1101 1122
    });
1102 1123

  
1103 1124
    tribute.attach(element);
test/functional/auto_completes_controller_test.rb
28 28
           :member_roles,
29 29
           :members,
30 30
           :enabled_modules,
31
           :journals, :journal_details
31
           :journals, :journal_details,
32
           :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
32 33

  
33 34
  def test_issues_should_not_be_case_sensitive
34 35
    get(
......
196 197
    assert_equal 10, json.count
197 198
    assert_equal Issue.last.id, json.first['id'].to_i
198 199
  end
200

  
201
  def test_wiki_pages_should_not_be_case_sensitive
202
    get(
203
      :wiki_pages,
204
      params: {
205
        project_id: 'ecookbook',
206
        q: 'pAgE'
207
      }
208
    )
209
    assert_response :success
210
    assert_include "Page_with_an_inline_image", response.body
211
  end
212

  
213
  def test_wiki_pages_without_project_should_search_all_projects
214
    get(:wiki_pages, params: {q: 'pAgE'})
215
    assert_response :success
216
    assert_include "Page_with_an_inline_image", response.body # project eCookbook
217
    assert_include "Start_page", response.body # project OnlineStore
218
  end
219

  
220
  def test_wiki_pages_should_return_json
221
    get(
222
      :wiki_pages,
223
      params: {
224
        project_id: 'ecookbook',
225
        q: 'Page_with_an_inline_image'
226
      }
227
    )
228
    assert_response :success
229
    json = ActiveSupport::JSON.decode(response.body)
230
    assert_kind_of Array, json
231
    issue = json.first
232
    assert_kind_of Hash, issue
233
    assert_equal 4, issue['id']
234
    assert_equal 'Page_with_an_inline_image', issue['value']
235
    assert_equal 'Page_with_an_inline_image', issue['label']
236
  end
237

  
238
  def test_wiki_pages_should_return_json_content_type_response
239
    get(
240
      :wiki_pages,
241
      params: {
242
        project_id: 'ecookbook',
243
        q: 'Page_with_an_inline_image'
244
      }
245
    )
246
    assert_response :success
247
    assert_include 'application/json', response.headers['Content-Type']
248
  end
249

  
250
  def test_wiki_pages_without_q_params_should_return_last_10_pages
251
    # There are 8 pages generated by fixtures
252
    # and we need three more to test the 10 limit
253
    wiki = Wiki.find_by(project: Project.first)
254
    3.times do |n|
255
      WikiPage.create(wiki: wiki, title: "test#{n}")
256
    end
257
    get :wiki_pages, params: { project_id: 'ecookbook' }
258
    assert_response :success
259
    json = ActiveSupport::JSON.decode(response.body)
260
    assert_equal 10, json.count
261
    assert_equal wiki.pages[-2].id, json.first['id'].to_i
262
  end
199 263
end
(4-4/6)