First version of exporting the Users to a CSV (#17217)
* feat: add the export route * feat: base export csv * refactor: move the svg into its own file * feat: add the export partial * feat: export teh correct fields etc. for the csv * user status helper * feat: ensure that we format the time * feat: add a spec for the CSV * remove space * remove puts * chore: remove blank space * feat: update traits * Update app/views/admin/users/export.csv.erb Co-authored-by: Jamie Gaskins <jgaskins@hey.com> * Update spec/requests/admin/users/users_export_spec.rb Co-authored-by: Jamie Gaskins <jgaskins@hey.com> * Update spec/requests/admin/users/users_export_spec.rb Co-authored-by: Jamie Gaskins <jgaskins@hey.com> * fix: export should not error for unregistered users Co-authored-by: Jamie Gaskins <jgaskins@hey.com>
This commit is contained in:
parent
2ba80fcd13
commit
aff29406ac
10 changed files with 138 additions and 2 deletions
|
|
@ -16,6 +16,15 @@ module Admin
|
|||
email_body
|
||||
].freeze
|
||||
|
||||
ATTIBUTES_FOR_CSV = %i[
|
||||
id name username email registered_at
|
||||
].freeze
|
||||
|
||||
ATTRIBUTES_FOR_LAST_ACTIVITY = %i[
|
||||
registered last_comment_at last_article_at latest_article_updated_at last_reacted_at profile_updated_at
|
||||
last_moderation_notification last_notification_activity
|
||||
].freeze
|
||||
|
||||
after_action only: %i[update user_status banish full_delete unpublish_all_articles merge] do
|
||||
Audit::Logger.log(:moderator, current_user, params.dup)
|
||||
end
|
||||
|
|
@ -69,6 +78,18 @@ module Admin
|
|||
redirect_to admin_user_path(params[:id])
|
||||
end
|
||||
|
||||
def export
|
||||
@users = User.select(ATTIBUTES_FOR_CSV + ATTRIBUTES_FOR_LAST_ACTIVITY).includes(:organizations)
|
||||
|
||||
respond_to do |format|
|
||||
format.csv do
|
||||
response.headers["Content-Type"] = "text/csv"
|
||||
response.headers["Content-Disposition"] = "attachment; filename=users.csv"
|
||||
render template: "admin/users/export"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def user_status
|
||||
@user = User.find(params[:id])
|
||||
begin
|
||||
|
|
|
|||
|
|
@ -31,5 +31,19 @@ module Admin
|
|||
"Resource Admin: #{user.roles.pluck(:resource_type).compact.join(', ')}"
|
||||
end
|
||||
end
|
||||
|
||||
def user_status(user)
|
||||
if user.suspended?
|
||||
"Suspended"
|
||||
elsif user.warned?
|
||||
"Warned"
|
||||
elsif user.comment_suspended?
|
||||
"Comment Suspended"
|
||||
elsif user.trusted?
|
||||
"Trusted"
|
||||
else
|
||||
"Good Standing"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
</div>
|
||||
<div>
|
||||
<dt class="color-base-60 fw-normal">Joined on</dt>
|
||||
<dd><%= user.registered_at.strftime("%d %b, %Y") %></dd>
|
||||
<dd><%= user.registered_at&.strftime("%d %b, %Y") %></dd>
|
||||
</div>
|
||||
</dl>
|
||||
<div>
|
||||
|
|
@ -83,7 +83,7 @@
|
|||
<td>
|
||||
<%= format_last_activity_timestamp(user.last_activity) %>
|
||||
<p class="fs-xs color-base-60">
|
||||
<%= user.registered_at.strftime("%d %b, %Y") %>
|
||||
<%= user.registered_at&.strftime("%d %b, %Y") %>
|
||||
</p>
|
||||
</td>
|
||||
<td>
|
||||
|
|
|
|||
6
app/views/admin/users/export.csv.erb
Normal file
6
app/views/admin/users/export.csv.erb
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<%- headers = ["Name", "Username", "Email address", "Status", "Joining date", "Last activity", "Organizations"] -%>
|
||||
<%= CSV.generate_line headers -%>
|
||||
<%- @users.each do |user| -%>
|
||||
<%- row = [user.name, user.username, user.email, user_status(user), user.registered_at&.strftime("%d %b, %Y"), user.last_activity&.strftime("%d %b, %Y"), user.organizations.pluck(:name)] -%>
|
||||
<%= CSV.generate_line(row).html_safe -%>
|
||||
<%- end -%>
|
||||
|
|
@ -24,6 +24,9 @@
|
|||
<div id="filter-users" class="hidden crayons-field flex-row items-center gap-2">
|
||||
<%= render "admin/users/index/filter_role_field", f: f %>
|
||||
</div>
|
||||
<div>
|
||||
<%= render "admin/users/index/controls/export", f: f %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
|
@ -36,6 +39,9 @@
|
|||
<div class="crayons-field flex-row items-center gap-2">
|
||||
<%= render "admin/users/index/filter_role_field", f: f %>
|
||||
</div>
|
||||
<div>
|
||||
<%= render "admin/users/index/controls/export", f: f %>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= paginate @users, theme: "admin", scope: @users, label: "Paginate users" %>
|
||||
</div>
|
||||
|
|
|
|||
5
app/views/admin/users/index/controls/_export.html.erb
Normal file
5
app/views/admin/users/index/controls/_export.html.erb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<a href="<%= export_admin_users_path %>.csv">
|
||||
<svg width="18" height="20" viewBox="0 0 18 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13 0L18 5V19.008C17.9997 19.2712 17.895 19.5235 17.7088 19.7095C17.5226 19.8955 17.2702 20 17.007 20H0.993C0.730378 19.9982 0.479017 19.8931 0.293218 19.7075C0.107418 19.5219 0.00209465 19.2706 0 19.008V0.992C0 0.444 0.445 0 0.993 0H13ZM10 10V6H8V10H5L9 14L13 10H10Z" fill="#404040" />
|
||||
</svg>
|
||||
</a>
|
||||
|
|
@ -45,6 +45,9 @@ namespace :admin do
|
|||
|
||||
resources :users, only: %i[index show update destroy] do
|
||||
resources :email_messages, only: :show
|
||||
collection do
|
||||
get "export"
|
||||
end
|
||||
|
||||
member do
|
||||
post "banish"
|
||||
|
|
|
|||
|
|
@ -110,6 +110,14 @@ FactoryBot.define do
|
|||
after(:build) { |user| user.add_role(:suspended) }
|
||||
end
|
||||
|
||||
trait :warned do
|
||||
after(:build) { |user| user.add_role(:warned) }
|
||||
end
|
||||
|
||||
trait :comment_suspended do
|
||||
after(:build) { |user| user.add_role(:comment_suspended) }
|
||||
end
|
||||
|
||||
trait :invited do
|
||||
after(:build) do |user|
|
||||
user.registered = false
|
||||
|
|
|
|||
|
|
@ -86,4 +86,36 @@ describe Admin::UsersHelper do
|
|||
expect(role).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "#user_status" do
|
||||
it "renders the proper status for a user that is suspended" do
|
||||
suspended_user = create(:user, :suspended)
|
||||
status = helper.user_status(suspended_user)
|
||||
expect(status).to eq "Suspended"
|
||||
end
|
||||
|
||||
it "renders the proper status for a user that is warned" do
|
||||
warned_user = create(:user, :warned)
|
||||
status = helper.user_status(warned_user)
|
||||
expect(status).to eq "Warned"
|
||||
end
|
||||
|
||||
it "renders the proper status for a user that is comment suspended" do
|
||||
comment_suspended_user = create(:user, :comment_suspended)
|
||||
status = helper.user_status(comment_suspended_user)
|
||||
expect(status).to eq "Comment Suspended"
|
||||
end
|
||||
|
||||
it "renders the proper status for a user that is trusted" do
|
||||
trusted_user = create(:user, :trusted)
|
||||
status = helper.user_status(trusted_user)
|
||||
expect(status).to eq "Trusted"
|
||||
end
|
||||
|
||||
it "renders the proper status for a user that is good standing" do
|
||||
good_standing_user = create(:user)
|
||||
status = helper.user_status(good_standing_user)
|
||||
expect(status).to eq "Good Standing"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
41
spec/requests/admin/users/users_export_spec.rb
Normal file
41
spec/requests/admin/users/users_export_spec.rb
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe "/admin/users/export", type: :request do
|
||||
let(:admin) do
|
||||
create(:user, :super_admin,
|
||||
name: "Admin1", username: "admin1", email: "admin1@gmail.com",
|
||||
registered_at: "2020-05-06T13:09:47+0000")
|
||||
end
|
||||
let!(:user) do
|
||||
create(:user, :org_member,
|
||||
name: "John Doe", username: "john_doe", email: "john_doe@gmail.com",
|
||||
registered_at: "2020-06-08T13:09:47+0000")
|
||||
end
|
||||
|
||||
before do
|
||||
sign_in(admin)
|
||||
get "#{export_admin_users_path}.csv"
|
||||
end
|
||||
|
||||
it "renders successfully" do
|
||||
expect(response).to have_http_status :ok
|
||||
end
|
||||
|
||||
it "renders the headers" do
|
||||
expect(response.body).to include("Name,Username,Email address,Status,Joining date,Last activity,Organizations")
|
||||
end
|
||||
|
||||
it "shows the correct number of total rows" do
|
||||
# This takes into account empty lines after each row
|
||||
expect(response.body.lines.count).to eq(3)
|
||||
end
|
||||
|
||||
it "shows the correct fields", :aggregate_failures do
|
||||
expect(response.body).to include('Admin1,admin1,admin1@gmail.com,Good Standing,"06 May, 2020","06 May, 2020",[]')
|
||||
# rubocop:disable Style/PercentLiteralDelimiters, Layout/LineLength
|
||||
expect(response.body).to include(
|
||||
%{John Doe,john_doe,john_doe@gmail.com,Good Standing,"08 Jun, 2020","08 Jun, 2020","[""#{user.organizations.first.name}""]"},
|
||||
)
|
||||
# rubocop:enable Style/PercentLiteralDelimiters, Layout/LineLength
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue