Project

General

Profile

Feature #37480 » feature-37480-v3.diff

Mizuki ISHIKAWA, 2026-02-12 05:08

View differences:

app/controllers/members_controller.rb
28 28

  
29 29
  require_sudo_mode :create, :update, :destroy
30 30

  
31
  include MembersHelper
32

  
31 33
  def index
32 34
    scope = @project.memberships
33
    @offset, @limit = api_offset_and_limit
34
    @member_count = scope.count
35
    @member_pages = Paginator.new @member_count, @limit, params['page']
36
    @offset ||= @member_pages.offset
37
    @members = scope.includes(:principal, :roles).order(:id).limit(@limit).offset(@offset).to_a
35
    @members = scope.includes(:principal, :roles).order(:id)
38 36

  
39 37
    respond_to do |format|
40 38
      format.html {head :not_acceptable}
41
      format.api
39
      format.api do
40
        @offset, @limit = api_offset_and_limit
41
        @member_count = scope.count
42
        @member_pages = Paginator.new @member_count, @limit, params['page']
43
        @offset ||= @member_pages.offset
44
        @members = @members.limit(@limit).offset(@offset).to_a
45
      end
46
      format.csv do
47
        send_data(members_to_csv(@members), type: 'text/csv; header=present', filename: "#{@project.identifier}-members.csv")
48
      end
42 49
    end
43 50
  end
44 51

  
app/helpers/members_helper.rb
62 62
      content_tag('em', content.join(", "), :class => "info")
63 63
    end
64 64
  end
65

  
66
  def members_to_csv(members)
67
    Redmine::Export::CSV.generate(encoding: params[:encoding]) do |csv|
68
      # csv headers
69
      csv << [l(:label_name), l(:label_role), l(:field_principal), l(:label_project)]
70

  
71
      # csv lines
72
      members.each do |member|
73
        member.roles.each do |role|
74
          csv << [
75
            member.principal.name,
76
            role.name,
77
            member.principal.is_a?(Group) ? l(:label_group) : l(:label_user),
78
            member.project.name
79
          ]
80
        end
81
      end
82
    end
83
  end
65 84
end
app/views/projects/settings/_members.html.erb
45 45
<% end %>
46 46
  </tbody>
47 47
</table>
48
<% other_formats_links do |f| %>
49
  <%= f.link_to_with_query_parameters "CSV", {}, :onclick => "showModal('csv-export-options', '330px'); return false;" %>
50
<% end %>
51
<div id="csv-export-options" style="display: none;">
52
  <h3 class="title"><%= l(:label_export_options, :export_format => 'CSV') %></h3>
53
  <%= form_tag(project_memberships_path(project_id: @project.id, format: 'csv'), :method => :get, :id => 'csv-export-form') do %>
54
  <%= export_csv_encoding_select_tag %>
55
  <p class="buttons">
56
    <%= submit_tag l(:button_export), :name => nil, :onclick => 'hideModal(this);', :data => {:disable_with => false} %>
57
    <%= link_to_function l(:button_cancel), 'hideModal(this);' %>
58
  </p>
59
  <% end %>
60
</div>
48 61
<% else %>
49 62
<p class="nodata"><%= l(:label_no_data) %></p>
50 63
<% end %>
config/locales/en.yml
657 657
  label_document_new: New document
658 658
  label_document_plural: Documents
659 659
  label_document_added: Document added
660
  label_name: Name
660 661
  label_role: Role
661 662
  label_role_plural: Roles
662 663
  label_role_new: New role
config/locales/ja.yml
493 493
  label_document_new: 新しい文書
494 494
  label_document_plural: 文書
495 495
  label_document_added: 文書の追加
496
  label_name: 名前
496 497
  label_role: ロール
497 498
  label_role_plural: ロール
498 499
  label_role_new: 新しいロール
test/functional/members_controller_test.rb
25 25
    @request.session[:user_id] = 2
26 26
  end
27 27

  
28
  def test_index_with_csv_format_should_export_csv
29
    project = Project.find(5)
30
    get(
31
      :index,
32
      params: {
33
        project_id: project.id,
34
        format: 'csv'
35
      }
36
    )
37
    assert_response :success
38
    assert_equal 'text/csv; header=present', response.media_type
39

  
40
    lines = response.body.chomp.split("\n")
41
    # Number of lines
42
    assert_equal project.memberships.sum{|m| m.roles.count } + 1, lines.size
43
    # Header
44
    assert_equal "Name,Role,User or Group,Project", lines.first
45
    # Details
46
    to_test = [
47
      'John Smith,Manager,User,Private child of eCookbook',
48
      'A Team,Manager,Group,Private child of eCookbook',
49
      'A Team,Developer,Group,Private child of eCookbook',
50
      'User Misc,Manager,User,Private child of eCookbook',
51
      'User Misc,Developer,User,Private child of eCookbook',
52
      'Redmine Admin,Manager,User,Private child of eCookbook'
53
    ]
54
    to_test.each do |expected|
55
      assert_includes lines, expected
56
    end
57
  end
58

  
28 59
  def test_new
29 60
    get(:new, :params => {:project_id => 1})
30 61
    assert_response :success
(4-4/4)