User export improvements 2 (#10560)
* FEATURE: Use predictable filenames inside the user archive export * FEATURE: Include badges in user archive export * FEATURE: Add user_visits table to the user archive export
This commit is contained in:
parent
43ffd4d28f
commit
5ec5fbd7ba
|
@ -13,13 +13,17 @@ module Jobs
|
||||||
COMPONENTS ||= %w(
|
COMPONENTS ||= %w(
|
||||||
user_archive
|
user_archive
|
||||||
user_archive_profile
|
user_archive_profile
|
||||||
|
badges
|
||||||
category_preferences
|
category_preferences
|
||||||
|
visits
|
||||||
)
|
)
|
||||||
|
|
||||||
HEADER_ATTRS_FOR ||= HashWithIndifferentAccess.new(
|
HEADER_ATTRS_FOR ||= HashWithIndifferentAccess.new(
|
||||||
user_archive: ['topic_title', 'categories', 'is_pm', 'post', 'like_count', 'reply_count', 'url', 'created_at'],
|
user_archive: ['topic_title', 'categories', 'is_pm', 'post', 'like_count', 'reply_count', 'url', 'created_at'],
|
||||||
user_archive_profile: ['location', 'website', 'bio', 'views'],
|
user_archive_profile: ['location', 'website', 'bio', 'views'],
|
||||||
|
badges: ['badge_id', 'badge_name', 'granted_at', 'post_id', 'seq', 'granted_manually', 'notification_id', 'featured_rank'],
|
||||||
category_preferences: ['category_id', 'category_names', 'notification_level', 'dismiss_new_timestamp'],
|
category_preferences: ['category_id', 'category_names', 'notification_level', 'dismiss_new_timestamp'],
|
||||||
|
visits: ['visited_at', 'posts_read', 'mobile', 'time_read'],
|
||||||
)
|
)
|
||||||
|
|
||||||
def execute(args)
|
def execute(args)
|
||||||
|
@ -36,13 +40,13 @@ module Jobs
|
||||||
if respond_to? filename_method
|
if respond_to? filename_method
|
||||||
h[:filename] = public_send(filename_method)
|
h[:filename] = public_send(filename_method)
|
||||||
else
|
else
|
||||||
h[:filename] = "#{name}-#{@current_user.username}-#{@timestamp}"
|
h[:filename] = name
|
||||||
end
|
end
|
||||||
components.push(h)
|
components.push(h)
|
||||||
end
|
end
|
||||||
|
|
||||||
export_title = 'user_archive'.titleize
|
export_title = 'user_archive'.titleize
|
||||||
filename = components.first[:filename]
|
filename = "user_archive-#{@current_user.username}-#{@timestamp}"
|
||||||
user_export = UserExport.create(file_name: filename, user_id: @current_user.id)
|
user_export = UserExport.create(file_name: filename, user_id: @current_user.id)
|
||||||
|
|
||||||
filename = "#{filename}-#{user_export.id}"
|
filename = "#{filename}-#{user_export.id}"
|
||||||
|
@ -126,6 +130,29 @@ module Jobs
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def badges_export
|
||||||
|
return enum_for(:badges_export) unless block_given?
|
||||||
|
|
||||||
|
UserBadge
|
||||||
|
.where(user_id: @current_user.id)
|
||||||
|
.joins(:badge)
|
||||||
|
.select(:badge_id, :granted_at, :post_id, :seq, :granted_by_id, :notification_id, :featured_rank)
|
||||||
|
.order(:granted_at)
|
||||||
|
.each do |ub|
|
||||||
|
yield [
|
||||||
|
ub.badge_id,
|
||||||
|
ub.badge.display_name,
|
||||||
|
ub.granted_at,
|
||||||
|
ub.post_id,
|
||||||
|
ub.seq,
|
||||||
|
# Hide the admin's identity, simply indicate human or system
|
||||||
|
User.human_user_id?(ub.granted_by_id),
|
||||||
|
ub.notification_id,
|
||||||
|
ub.featured_rank,
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def category_preferences_export
|
def category_preferences_export
|
||||||
return enum_for(:category_preferences_export) unless block_given?
|
return enum_for(:category_preferences_export) unless block_given?
|
||||||
|
|
||||||
|
@ -142,6 +169,22 @@ module Jobs
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def visits_export
|
||||||
|
return enum_for(:visits_export) unless block_given?
|
||||||
|
|
||||||
|
UserVisit
|
||||||
|
.where(user_id: @current_user.id)
|
||||||
|
.order(visited_at: :asc)
|
||||||
|
.each do |uv|
|
||||||
|
yield [
|
||||||
|
uv.visited_at,
|
||||||
|
uv.posts_read,
|
||||||
|
uv.mobile,
|
||||||
|
uv.time_read,
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def get_header(entity)
|
def get_header(entity)
|
||||||
if entity == 'user_list'
|
if entity == 'user_list'
|
||||||
header_array = HEADER_ATTRS_FOR['user_list'] + HEADER_ATTRS_FOR['user_stats'] + HEADER_ATTRS_FOR['user_profile']
|
header_array = HEADER_ATTRS_FOR['user_list'] + HEADER_ATTRS_FOR['user_stats'] + HEADER_ATTRS_FOR['user_profile']
|
||||||
|
|
|
@ -73,8 +73,8 @@ describe Jobs::ExportUserArchive do
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(files.size).to eq(Jobs::ExportUserArchive::COMPONENTS.length)
|
expect(files.size).to eq(Jobs::ExportUserArchive::COMPONENTS.length)
|
||||||
expect(files.find { |f| f.match 'user_archive-john_doe-' }).to_not be_nil
|
expect(files.find { |f| f == 'user_archive.csv' }).to_not be_nil
|
||||||
expect(files.find { |f| f.match 'user_archive_profile-john_doe-' }).to_not be_nil
|
expect(files.find { |f| f == 'category_preferences.csv' }).to_not be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -149,6 +149,37 @@ describe Jobs::ExportUserArchive do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'badges' do
|
||||||
|
let(:component) { 'badges' }
|
||||||
|
|
||||||
|
let(:admin) { Fabricate(:admin) }
|
||||||
|
let(:badge1) { Fabricate(:badge) }
|
||||||
|
let(:badge2) { Fabricate(:badge, multiple_grant: true) }
|
||||||
|
let(:badge3) { Fabricate(:badge, multiple_grant: true) }
|
||||||
|
let(:day_ago) { 1.day.ago }
|
||||||
|
|
||||||
|
it 'properly includes badge records' do
|
||||||
|
grant_start = Time.now.utc
|
||||||
|
BadgeGranter.grant(badge1, user)
|
||||||
|
BadgeGranter.grant(badge2, user)
|
||||||
|
BadgeGranter.grant(badge2, user, granted_by: admin)
|
||||||
|
BadgeGranter.grant(badge3, user, post_id: Fabricate(:post).id)
|
||||||
|
BadgeGranter.grant(badge3, user, post_id: Fabricate(:post).id)
|
||||||
|
BadgeGranter.grant(badge3, user, post_id: Fabricate(:post).id)
|
||||||
|
|
||||||
|
data, csv_out = make_component_csv
|
||||||
|
expect(data.length).to eq(6)
|
||||||
|
|
||||||
|
expect(data[0]['badge_id']).to eq(badge1.id.to_s)
|
||||||
|
expect(data[0]['badge_name']).to eq(badge1.display_name)
|
||||||
|
expect(data[0]['featured_rank']).to_not eq('')
|
||||||
|
expect(DateTime.parse(data[0]['granted_at'])).to be >= DateTime.parse(grant_start.to_s)
|
||||||
|
expect(data[2]['granted_manually']).to eq('true')
|
||||||
|
expect(Post.find(data[3]['post_id'])).to_not be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
context 'category_preferences' do
|
context 'category_preferences' do
|
||||||
let(:component) { 'category_preferences' }
|
let(:component) { 'category_preferences' }
|
||||||
|
|
||||||
|
@ -201,4 +232,30 @@ describe Jobs::ExportUserArchive do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'visits' do
|
||||||
|
let(:component) { 'visits' }
|
||||||
|
let(:user2) { Fabricate(:user) }
|
||||||
|
|
||||||
|
it 'correctly exports the UserVisit table' do
|
||||||
|
freeze_time '2017-03-01 12:00'
|
||||||
|
|
||||||
|
UserVisit.create(user_id: user.id, visited_at: 1.minute.ago, posts_read: 1, mobile: false, time_read: 10)
|
||||||
|
UserVisit.create(user_id: user.id, visited_at: 2.days.ago, posts_read: 2, mobile: false, time_read: 20)
|
||||||
|
UserVisit.create(user_id: user.id, visited_at: 1.week.ago, posts_read: 3, mobile: true, time_read: 30)
|
||||||
|
UserVisit.create(user_id: user.id, visited_at: 1.year.ago, posts_read: 4, mobile: false, time_read: 40)
|
||||||
|
UserVisit.create(user_id: user2.id, visited_at: 1.minute.ago, posts_read: 1, mobile: false, time_read: 50)
|
||||||
|
|
||||||
|
data, csv_out = make_component_csv
|
||||||
|
|
||||||
|
# user2's data is not mixed in
|
||||||
|
expect(data.length).to eq(4)
|
||||||
|
expect(data.find { |r| r['time_read'] == 50 }).to be_nil
|
||||||
|
|
||||||
|
expect(data[0]['visited_at']).to eq('2016-03-01')
|
||||||
|
expect(data[0]['posts_read']).to eq('4')
|
||||||
|
expect(data[0]['time_read']).to eq('40')
|
||||||
|
expect(data[1]['mobile']).to eq('true')
|
||||||
|
expect(data[3]['visited_at']).to eq('2017-03-01')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue