Add three reports (#14338)
* Add report top_users_by_received_likes * Add report top_users_by_received_likes_from_inferior_trust_level * Add report top_users_by_likes_received_from_a_variety_of_people * Add test to report_top_users_by_received_likes * add top_users_by_likes_received_from_a_variety_of_people report test * add top_users_by_likes_received_from_inferior_trust_level report tests
This commit is contained in:
parent
2f04a9b9fb
commit
9b5836aa1d
|
@ -0,0 +1,58 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Reports::TopUsersByLikesReceived
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
class_methods do
|
||||||
|
def report_top_users_by_likes_received(report)
|
||||||
|
report.icon = 'heart'
|
||||||
|
report.data = []
|
||||||
|
|
||||||
|
report.modes = [:table]
|
||||||
|
|
||||||
|
report.dates_filtering = true
|
||||||
|
|
||||||
|
report.labels = [
|
||||||
|
{
|
||||||
|
type: :user,
|
||||||
|
properties: {
|
||||||
|
id: :user_id,
|
||||||
|
username: :username,
|
||||||
|
avatar: :user_avatar_template,
|
||||||
|
},
|
||||||
|
title: I18n.t("reports.top_users_by_likes_received.labels.user")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: :number,
|
||||||
|
property: :qtt_like,
|
||||||
|
title: I18n.t("reports.top_users_by_likes_received.labels.qtt_like")
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
sql = <<~SQL
|
||||||
|
SELECT
|
||||||
|
ua.user_id AS user_id,
|
||||||
|
u.username as username,
|
||||||
|
u.uploaded_avatar_id as uploaded_avatar_id,
|
||||||
|
COUNT(*) qtt_like
|
||||||
|
FROM user_actions ua
|
||||||
|
INNER JOIN users u on ua.user_id = u.id
|
||||||
|
WHERE ua.created_at::date BETWEEN :start_date AND :end_date
|
||||||
|
AND ua.action_type = 2
|
||||||
|
GROUP BY ua.user_id, u.username, u.uploaded_avatar_id
|
||||||
|
ORDER BY qtt_like DESC
|
||||||
|
LIMIT 10
|
||||||
|
SQL
|
||||||
|
|
||||||
|
DB.query(sql, start_date: report.start_date, end_date: report.end_date).each do |row|
|
||||||
|
report.data << {
|
||||||
|
user_id: row.user_id,
|
||||||
|
username: row.username,
|
||||||
|
user_avatar_template: User.avatar_template(row.username, row.uploaded_avatar_id),
|
||||||
|
qtt_like: row.qtt_like,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,60 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Reports::TopUsersByLikesReceivedFromAVarietyOfPeople
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
class_methods do
|
||||||
|
def report_top_users_by_likes_received_from_a_variety_of_people(report)
|
||||||
|
report.icon = 'heart'
|
||||||
|
report.data = []
|
||||||
|
|
||||||
|
report.modes = [:table]
|
||||||
|
|
||||||
|
report.dates_filtering = true
|
||||||
|
|
||||||
|
report.labels = [
|
||||||
|
{
|
||||||
|
type: :user,
|
||||||
|
properties: {
|
||||||
|
id: :user_id,
|
||||||
|
username: :username,
|
||||||
|
avatar: :user_avatar_template,
|
||||||
|
},
|
||||||
|
title: I18n.t("reports.top_users_by_likes_received_from_a_variety_of_people.labels.user")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: :number,
|
||||||
|
property: :qtt_like,
|
||||||
|
title: I18n.t("reports.top_users_by_likes_received_from_a_variety_of_people.labels.qtt_like")
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
sql = <<~SQL
|
||||||
|
SELECT
|
||||||
|
p.user_id,
|
||||||
|
u.username as username,
|
||||||
|
u.uploaded_avatar_id as uploaded_avatar_id,
|
||||||
|
COUNT(DISTINCT ua.user_id) qtt_like
|
||||||
|
FROM user_actions ua
|
||||||
|
INNER JOIN posts p ON p.id = ua.target_post_id
|
||||||
|
INNER JOIN users u on p.user_id = u.id
|
||||||
|
WHERE ua.created_at::date BETWEEN :start_date AND :end_date
|
||||||
|
AND ua.action_type = 1
|
||||||
|
AND p.user_id > 0
|
||||||
|
GROUP BY p.user_id, u.username, u.uploaded_avatar_id
|
||||||
|
ORDER BY qtt_like DESC
|
||||||
|
LIMIT 10
|
||||||
|
SQL
|
||||||
|
|
||||||
|
DB.query(sql, start_date: report.start_date, end_date: report.end_date).each do |row|
|
||||||
|
report.data << {
|
||||||
|
user_id: row.user_id,
|
||||||
|
username: row.username,
|
||||||
|
user_avatar_template: User.avatar_template(row.username, row.uploaded_avatar_id),
|
||||||
|
qtt_like: row.qtt_like,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,71 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Reports::TopUsersByLikesReceivedFromInferiorTrustLevel
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
class_methods do
|
||||||
|
def report_top_users_by_likes_received_from_inferior_trust_level(report)
|
||||||
|
report.icon = 'heart'
|
||||||
|
report.data = []
|
||||||
|
|
||||||
|
report.modes = [:table]
|
||||||
|
|
||||||
|
report.dates_filtering = true
|
||||||
|
|
||||||
|
report.labels = [
|
||||||
|
{
|
||||||
|
type: :user,
|
||||||
|
properties: {
|
||||||
|
id: :user_id,
|
||||||
|
username: :username,
|
||||||
|
avatar: :user_avatar_template,
|
||||||
|
},
|
||||||
|
title: I18n.t("reports.top_users_by_likes_received_from_inferior_trust_level.labels.user")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: :number,
|
||||||
|
property: :trust_level,
|
||||||
|
title: I18n.t("reports.top_users_by_likes_received_from_inferior_trust_level.labels.trust_level")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: :number,
|
||||||
|
property: :qtt_like,
|
||||||
|
title: I18n.t("reports.top_users_by_likes_received_from_inferior_trust_level.labels.qtt_like")
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
sql = <<~SQL
|
||||||
|
WITH user_liked_tl_lower AS (
|
||||||
|
SELECT
|
||||||
|
users.id user_id,
|
||||||
|
users.username as username,
|
||||||
|
users.uploaded_avatar_id as uploaded_avatar_id,
|
||||||
|
users.trust_level,
|
||||||
|
COUNT(*) qtt_like,
|
||||||
|
rank() OVER (PARTITION BY users.trust_level ORDER BY COUNT(*) DESC)
|
||||||
|
FROM users
|
||||||
|
INNER JOIN posts p ON p.user_id = users.id
|
||||||
|
INNER JOIN user_actions ua ON ua.target_post_id = p.id AND ua.action_type = 1
|
||||||
|
INNER JOIN users u_liked ON ua.user_id = u_liked.id AND u_liked.trust_level < users.trust_level
|
||||||
|
WHERE ua.created_at::date BETWEEN :start_date AND :end_date
|
||||||
|
GROUP BY users.id
|
||||||
|
ORDER BY trust_level DESC, qtt_like DESC
|
||||||
|
)
|
||||||
|
|
||||||
|
SELECT * FROM user_liked_tl_lower
|
||||||
|
WHERE rank <= 10
|
||||||
|
SQL
|
||||||
|
|
||||||
|
DB.query(sql, start_date: report.start_date, end_date: report.end_date).each do |row|
|
||||||
|
report.data << {
|
||||||
|
user_id: row.user_id,
|
||||||
|
username: row.username,
|
||||||
|
user_avatar_template: User.avatar_template(row.username, row.uploaded_avatar_id),
|
||||||
|
trust_level: row.trust_level,
|
||||||
|
qtt_like: row.qtt_like,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -46,6 +46,9 @@ class Report
|
||||||
include Reports::ModeratorWarningPrivateMessages
|
include Reports::ModeratorWarningPrivateMessages
|
||||||
include Reports::ProfileViews
|
include Reports::ProfileViews
|
||||||
include Reports::TopUploads
|
include Reports::TopUploads
|
||||||
|
include Reports::TopUsersByLikesReceived
|
||||||
|
include Reports::TopUsersByLikesReceivedFromInferiorTrustLevel
|
||||||
|
include Reports::TopUsersByLikesReceivedFromAVarietyOfPeople
|
||||||
|
|
||||||
attr_accessor :type, :data, :total, :prev30Days, :start_date,
|
attr_accessor :type, :data, :total, :prev30Days, :start_date,
|
||||||
:end_date, :labels, :prev_period, :facets, :limit, :average,
|
:end_date, :labels, :prev_period, :facets, :limit, :average,
|
||||||
|
|
|
@ -1420,6 +1420,25 @@ en:
|
||||||
ignores_count: Ignores count
|
ignores_count: Ignores count
|
||||||
mutes_count: Mutes count
|
mutes_count: Mutes count
|
||||||
description: "Users who have been muted and/or ignored by many other users."
|
description: "Users who have been muted and/or ignored by many other users."
|
||||||
|
top_users_by_likes_received:
|
||||||
|
title: "Top Users by likes received"
|
||||||
|
labels:
|
||||||
|
user: User
|
||||||
|
qtt_like: Likes Received
|
||||||
|
description: "Top 10 users who have been received more likes."
|
||||||
|
top_users_by_likes_received_from_inferior_trust_level:
|
||||||
|
title: "Top Users by likes received from a user with a lower trust level"
|
||||||
|
labels:
|
||||||
|
user: User
|
||||||
|
trust_level: Trust level
|
||||||
|
qtt_like: Likes Received
|
||||||
|
description: "Top 10 users in a higher trust level being liked by people in a lower trust level."
|
||||||
|
top_users_by_likes_received_from_a_variety_of_people:
|
||||||
|
title: "Top Users by likes received from a variety of people"
|
||||||
|
labels:
|
||||||
|
user: User
|
||||||
|
qtt_like: Likes Received
|
||||||
|
description: "Top 10 users who have had the likes from a wide range of people."
|
||||||
|
|
||||||
dashboard:
|
dashboard:
|
||||||
rails_env_warning: "Your server is running in %{env} mode."
|
rails_env_warning: "Your server is running in %{env} mode."
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# version check: https://github.com/ImageMagick/ImageMagick/releases
|
||||||
|
IMAGE_MAGICK_VERSION="7.0.11-13"
|
||||||
|
IMAGE_MAGICK_HASH="fc454be622724c6224fa6c8230bb9c50191a05fbf05b9c9c25aa3e5497090b83"
|
||||||
|
|
||||||
|
# version check: https://github.com/strukturag/libheif/releases
|
||||||
|
LIBHEIF_VERSION="1.12.0"
|
||||||
|
LIBHEIF_HASH="086145b0d990182a033b0011caadb1b642da84f39ab83aa66d005610650b3c65"
|
||||||
|
|
||||||
|
# version check: https://aomedia.googlesource.com/aom
|
||||||
|
LIB_AOM_VERSION="3.1.0"
|
||||||
|
|
||||||
|
# We use debian, but GitHub CI is stuck on Ubuntu Bionic, so this must be compatible with both
|
||||||
|
LIBJPEGTURBO=$(cat /etc/issue | grep -qi Debian && echo 'libjpeg62-turbo libjpeg62-turbo-dev' || echo 'libjpeg-turbo8 libjpeg-turbo8-dev')
|
||||||
|
|
||||||
|
PREFIX=/usr/local
|
||||||
|
WDIR=/tmp/imagemagick
|
||||||
|
|
||||||
|
# Install build deps
|
||||||
|
apt -y -q remove imagemagick
|
||||||
|
apt -y -q install git make gcc pkg-config autoconf curl g++ \
|
||||||
|
yasm cmake \
|
||||||
|
libde265-0 libde265-dev ${LIBJPEGTURBO} x265 libx265-dev libtool \
|
||||||
|
libpng16-16 libpng-dev ${LIBJPEGTURBO} libwebp6 libwebp-dev libgomp1 libwebpmux3 libwebpdemux2 ghostscript libxml2-dev libxml2-utils \
|
||||||
|
libbz2-dev gsfonts libtiff-dev libfreetype6-dev libjpeg-dev
|
||||||
|
|
||||||
|
mkdir -p $WDIR
|
||||||
|
cd $WDIR
|
||||||
|
|
||||||
|
# Building libaom
|
||||||
|
git clone https://aomedia.googlesource.com/aom
|
||||||
|
cd aom && git checkout v${LIB_AOM_VERSION} && cd ..
|
||||||
|
mkdir build_aom
|
||||||
|
cd build_aom
|
||||||
|
cmake ../aom/ -DENABLE_TESTS=0 -DBUILD_SHARED_LIBS=1 && make && make install
|
||||||
|
ldconfig /usr/local/lib
|
||||||
|
cd ..
|
||||||
|
rm -rf aom
|
||||||
|
rm -rf build_aom
|
||||||
|
|
||||||
|
# Build and install libheif
|
||||||
|
cd $WDIR
|
||||||
|
wget -O $WDIR/libheif.tar.gz "https://github.com/strukturag/libheif/archive/v$LIBHEIF_VERSION.tar.gz"
|
||||||
|
sha256sum $WDIR/libheif.tar.gz
|
||||||
|
echo "$LIBHEIF_HASH $WDIR/libheif.tar.gz" | sha256sum -c
|
||||||
|
tar -xzvf $WDIR/libheif.tar.gz
|
||||||
|
cd libheif-$LIBHEIF_VERSION
|
||||||
|
./autogen.sh
|
||||||
|
./configure
|
||||||
|
make && make install
|
||||||
|
|
||||||
|
# Build and install ImageMagick
|
||||||
|
wget -O $WDIR/ImageMagick.tar.gz "https://github.com/ImageMagick/ImageMagick/archive/$IMAGE_MAGICK_VERSION.tar.gz"
|
||||||
|
sha256sum $WDIR/ImageMagick.tar.gz
|
||||||
|
echo "$IMAGE_MAGICK_HASH $WDIR/ImageMagick.tar.gz" | sha256sum -c
|
||||||
|
IMDIR=$WDIR/$(tar tzf $WDIR/ImageMagick.tar.gz --wildcards "ImageMagick-*/configure" |cut -d/ -f1)
|
||||||
|
tar zxf $WDIR/ImageMagick.tar.gz -C $WDIR
|
||||||
|
cd $IMDIR
|
||||||
|
PKG_CONF_LIBDIR=$PREFIX/lib LDFLAGS=-L$PREFIX/lib CFLAGS=-I$PREFIX/include ./configure \
|
||||||
|
--prefix=$PREFIX \
|
||||||
|
--enable-static \
|
||||||
|
--enable-bounds-checking \
|
||||||
|
--enable-hdri \
|
||||||
|
--enable-hugepages \
|
||||||
|
--with-threads \
|
||||||
|
--with-modules \
|
||||||
|
--with-quantum-depth=16 \
|
||||||
|
--without-magick-plus-plus \
|
||||||
|
--with-bzlib \
|
||||||
|
--with-zlib \
|
||||||
|
--without-autotrace \
|
||||||
|
--with-freetype \
|
||||||
|
--with-jpeg \
|
||||||
|
--without-lcms \
|
||||||
|
--with-lzma \
|
||||||
|
--with-png \
|
||||||
|
--with-tiff \
|
||||||
|
--with-heic \
|
||||||
|
--with-webp
|
||||||
|
make all && make install
|
||||||
|
|
||||||
|
cd $HOME
|
||||||
|
rm -rf $WDIR
|
||||||
|
ldconfig /usr/local/lib
|
|
@ -1325,4 +1325,108 @@ describe Report do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'top_users_by_likes_received' do
|
||||||
|
let(:report) { Report.find('top_users_by_likes_received') }
|
||||||
|
|
||||||
|
include_examples 'no data'
|
||||||
|
|
||||||
|
context 'with data' do
|
||||||
|
before do
|
||||||
|
user_1 = Fabricate(:user, username: "jonah")
|
||||||
|
user_2 = Fabricate(:user, username: "jake")
|
||||||
|
user_3 = Fabricate(:user, username: "john")
|
||||||
|
|
||||||
|
3.times { UserAction.create!(user_id: user_1.id, action_type: UserAction::WAS_LIKED) }
|
||||||
|
9.times { UserAction.create!(user_id: user_2.id, action_type: UserAction::WAS_LIKED) }
|
||||||
|
6.times { UserAction.create!(user_id: user_3.id, action_type: UserAction::WAS_LIKED) }
|
||||||
|
end
|
||||||
|
|
||||||
|
it "with category filtering" do
|
||||||
|
report = Report.find('top_users_by_likes_received')
|
||||||
|
|
||||||
|
expect(report.data.length).to eq(3)
|
||||||
|
expect(report.data[0][:username]).to eq("jake")
|
||||||
|
expect(report.data[1][:username]).to eq("john")
|
||||||
|
expect(report.data[2][:username]).to eq("jonah")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'top_users_by_likes_received_from_a_variety_of_people' do
|
||||||
|
let(:report) { Report.find('top_users_by_likes_received_from_a_variety_of_people') }
|
||||||
|
|
||||||
|
include_examples 'no data'
|
||||||
|
|
||||||
|
context 'with data' do
|
||||||
|
before do
|
||||||
|
user_1 = Fabricate(:user, username: "jonah")
|
||||||
|
user_2 = Fabricate(:user, username: "jake")
|
||||||
|
user_3 = Fabricate(:user, username: "john")
|
||||||
|
user_4 = Fabricate(:user, username: "joseph")
|
||||||
|
user_5 = Fabricate(:user, username: "joanne")
|
||||||
|
user_6 = Fabricate(:user, username: "jerome")
|
||||||
|
|
||||||
|
topic_1 = Fabricate(:topic, user: user_1)
|
||||||
|
topic_2 = Fabricate(:topic, user: user_2)
|
||||||
|
topic_3 = Fabricate(:topic, user: user_3)
|
||||||
|
|
||||||
|
post_1 = Fabricate(:post, topic: topic_1, user: user_1)
|
||||||
|
post_2 = Fabricate(:post, topic: topic_2, user: user_2)
|
||||||
|
post_3 = Fabricate(:post, topic: topic_3, user: user_3)
|
||||||
|
|
||||||
|
3.times { UserAction.create!(user_id: user_4.id, target_post_id: post_1.id, action_type: UserAction::LIKE) }
|
||||||
|
6.times { UserAction.create!(user_id: user_5.id, target_post_id: post_2.id, action_type: UserAction::LIKE) }
|
||||||
|
9.times { UserAction.create!(user_id: user_6.id, target_post_id: post_3.id, action_type: UserAction::LIKE) }
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
it "with category filtering" do
|
||||||
|
report = Report.find('top_users_by_likes_received_from_a_variety_of_people')
|
||||||
|
|
||||||
|
expect(report.data.length).to eq(3)
|
||||||
|
expect(report.data[0][:username]).to eq("jonah")
|
||||||
|
expect(report.data[1][:username]).to eq("jake")
|
||||||
|
expect(report.data[2][:username]).to eq("john")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'top_users_by_likes_received_from_inferior_trust_level' do
|
||||||
|
let(:report) { Report.find('top_users_by_likes_received_from_inferior_trust_level') }
|
||||||
|
|
||||||
|
include_examples 'no data'
|
||||||
|
|
||||||
|
context 'with data' do
|
||||||
|
before do
|
||||||
|
user_1 = Fabricate(:user, username: "jonah", trust_level: 2)
|
||||||
|
user_2 = Fabricate(:user, username: "jake", trust_level: 2)
|
||||||
|
user_3 = Fabricate(:user, username: "john", trust_level: 2)
|
||||||
|
user_4 = Fabricate(:user, username: "joseph", trust_level: 1)
|
||||||
|
user_5 = Fabricate(:user, username: "joanne", trust_level: 1)
|
||||||
|
user_6 = Fabricate(:user, username: "jerome", trust_level: 2)
|
||||||
|
|
||||||
|
topic_1 = Fabricate(:topic, user: user_1)
|
||||||
|
topic_2 = Fabricate(:topic, user: user_2)
|
||||||
|
topic_3 = Fabricate(:topic, user: user_3)
|
||||||
|
|
||||||
|
post_1 = Fabricate(:post, topic: topic_1, user: user_1)
|
||||||
|
post_2 = Fabricate(:post, topic: topic_2, user: user_2)
|
||||||
|
post_3 = Fabricate(:post, topic: topic_3, user: user_3)
|
||||||
|
|
||||||
|
3.times { UserAction.create!(user_id: user_4.id, target_post_id: post_1.id, action_type: UserAction::LIKE) }
|
||||||
|
6.times { UserAction.create!(user_id: user_5.id, target_post_id: post_2.id, action_type: UserAction::LIKE) }
|
||||||
|
9.times { UserAction.create!(user_id: user_6.id, target_post_id: post_3.id, action_type: UserAction::LIKE) }
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
it "with category filtering" do
|
||||||
|
report = Report.find('top_users_by_likes_received_from_inferior_trust_level')
|
||||||
|
|
||||||
|
expect(report.data.length).to eq(2)
|
||||||
|
expect(report.data[0][:username]).to eq("jake")
|
||||||
|
expect(report.data[1][:username]).to eq("jonah")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue