mirror of
https://github.com/discourse/discourse.git
synced 2025-06-06 23:07:28 +08:00
FEATURE: Add Top Uploads
report (#6825)
Co-Authored-By: I am very Pro-Grammer. <khalilovcmded@users.noreply.github.com>
This commit is contained in:
@ -272,6 +272,7 @@ const Report = Discourse.Model.extend({
|
|||||||
if (type === "seconds") return this._secondsLabel(value);
|
if (type === "seconds") return this._secondsLabel(value);
|
||||||
if (type === "link") return this._linkLabel(label.properties, row);
|
if (type === "link") return this._linkLabel(label.properties, row);
|
||||||
if (type === "percent") return this._percentLabel(value);
|
if (type === "percent") return this._percentLabel(value);
|
||||||
|
if (type === "bytes") return this._bytesLabel(value);
|
||||||
if (type === "number") {
|
if (type === "number") {
|
||||||
return this._numberLabel(value, opts);
|
return this._numberLabel(value, opts);
|
||||||
}
|
}
|
||||||
@ -381,6 +382,13 @@ const Report = Discourse.Model.extend({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_bytesLabel(value) {
|
||||||
|
return {
|
||||||
|
value,
|
||||||
|
formatedValue: I18n.toHumanSize(value)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
_dateLabel(value, date, format = "LL") {
|
_dateLabel(value, date, format = "LL") {
|
||||||
return {
|
return {
|
||||||
value,
|
value,
|
||||||
|
@ -1433,6 +1433,72 @@ class Report
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.report_top_uploads(report)
|
||||||
|
report.modes = [:table]
|
||||||
|
|
||||||
|
report.labels = [
|
||||||
|
{
|
||||||
|
type: :link,
|
||||||
|
properties: [
|
||||||
|
:file_url,
|
||||||
|
:file_name,
|
||||||
|
],
|
||||||
|
title: I18n.t("reports.top_uploads.labels.filename")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: :user,
|
||||||
|
properties: {
|
||||||
|
username: :author_username,
|
||||||
|
id: :author_id,
|
||||||
|
avatar: :author_avatar_template,
|
||||||
|
},
|
||||||
|
title: I18n.t("reports.top_uploads.labels.author")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: :text,
|
||||||
|
property: :extension,
|
||||||
|
title: I18n.t("reports.top_uploads.labels.extension")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: :bytes,
|
||||||
|
property: :filesize,
|
||||||
|
title: I18n.t("reports.top_uploads.labels.filesize")
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
report.data = []
|
||||||
|
|
||||||
|
sql = <<~SQL
|
||||||
|
SELECT
|
||||||
|
u.id as user_id,
|
||||||
|
u.username,
|
||||||
|
u.uploaded_avatar_id,
|
||||||
|
up.filesize,
|
||||||
|
up.original_filename,
|
||||||
|
up.extension,
|
||||||
|
up.url
|
||||||
|
FROM uploads up
|
||||||
|
JOIN users u
|
||||||
|
ON u.id = up.user_id
|
||||||
|
WHERE up.created_at >= '#{report.start_date}' AND up.created_at <= '#{report.end_date}'
|
||||||
|
ORDER BY up.filesize DESC
|
||||||
|
LIMIT #{report.limit || 250}
|
||||||
|
SQL
|
||||||
|
|
||||||
|
DB.query(sql).each do |row|
|
||||||
|
data = {}
|
||||||
|
data[:author_id] = row.user_id
|
||||||
|
data[:author_username] = row.username
|
||||||
|
data[:author_avatar_template] = User.avatar_template(row.username, row.uploaded_avatar_id)
|
||||||
|
data[:filesize] = row.filesize
|
||||||
|
data[:extension] = row.extension
|
||||||
|
data[:file_url] = Discourse.store.cdn_url(row.url)
|
||||||
|
data[:file_name] = row.original_filename.truncate(25)
|
||||||
|
|
||||||
|
report.data << data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
DiscourseEvent.on(:site_setting_saved) do |site_setting|
|
DiscourseEvent.on(:site_setting_saved) do |site_setting|
|
||||||
if ["backup_location", "s3_backup_bucket"].include?(site_setting.name.to_s)
|
if ["backup_location", "s3_backup_bucket"].include?(site_setting.name.to_s)
|
||||||
clear_cache(:storage_stats)
|
clear_cache(:storage_stats)
|
||||||
|
@ -1171,6 +1171,14 @@ en:
|
|||||||
location: Location
|
location: Location
|
||||||
login_at: Login at
|
login_at: Login at
|
||||||
description: "List of admin and moderator login times with locations."
|
description: "List of admin and moderator login times with locations."
|
||||||
|
top_uploads:
|
||||||
|
title: "Top Uploads"
|
||||||
|
labels:
|
||||||
|
filename: Filename
|
||||||
|
extension: Extension
|
||||||
|
author: Author
|
||||||
|
filesize: File size
|
||||||
|
description: "List all uploads by extension, filesize and author."
|
||||||
|
|
||||||
dashboard:
|
dashboard:
|
||||||
rails_env_warning: "Your server is running in %{env} mode."
|
rails_env_warning: "Your server is running in %{env} mode."
|
||||||
|
@ -1028,4 +1028,45 @@ describe Report do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "report_top_uploads" do
|
||||||
|
let(:report) { Report.find("top_uploads") }
|
||||||
|
let(:tarek) { Fabricate(:admin, username: "tarek") }
|
||||||
|
let(:khalil) { Fabricate(:admin, username: "khalil") }
|
||||||
|
|
||||||
|
context "with data" do
|
||||||
|
let!(:tarek_upload) do
|
||||||
|
Fabricate(:upload, user: tarek,
|
||||||
|
url: "/uploads/default/original/1X/tarek.jpg",
|
||||||
|
extension: "jpg",
|
||||||
|
original_filename: "tarek.jpg",
|
||||||
|
filesize: 1000)
|
||||||
|
end
|
||||||
|
let!(:khalil_upload) do
|
||||||
|
Fabricate(:upload, user: khalil,
|
||||||
|
url: "/uploads/default/original/1X/khalil.png",
|
||||||
|
extension: "png",
|
||||||
|
original_filename: "khalil.png",
|
||||||
|
filesize: 2000)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "works" do
|
||||||
|
expect(report.data.length).to eq(2)
|
||||||
|
expect_row_to_be_equal(report.data[0], khalil, khalil_upload)
|
||||||
|
expect_row_to_be_equal(report.data[1], tarek, tarek_upload)
|
||||||
|
end
|
||||||
|
|
||||||
|
def expect_row_to_be_equal(row, user, upload)
|
||||||
|
expect(row[:author_id]).to eq(user.id)
|
||||||
|
expect(row[:author_username]).to eq(user.username)
|
||||||
|
expect(row[:author_avatar_template]).to eq(User.avatar_template(user.username, user.uploaded_avatar_id))
|
||||||
|
expect(row[:filesize]).to eq(upload.filesize)
|
||||||
|
expect(row[:extension]).to eq(upload.extension)
|
||||||
|
expect(row[:file_url]).to eq(Discourse.store.cdn_url(upload.url))
|
||||||
|
expect(row[:file_name]).to eq(upload.original_filename.truncate(25))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
include_examples "no data"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -404,7 +404,8 @@ QUnit.test("computed labels", assert => {
|
|||||||
topic_id: 2,
|
topic_id: 2,
|
||||||
topic_title: "Test topic",
|
topic_title: "Test topic",
|
||||||
post_number: 3,
|
post_number: 3,
|
||||||
post_raw: "This is the beginning of"
|
post_raw: "This is the beginning of",
|
||||||
|
filesize: 582641
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -437,7 +438,8 @@ QUnit.test("computed labels", assert => {
|
|||||||
truncated_raw: "post_raw"
|
truncated_raw: "post_raw"
|
||||||
},
|
},
|
||||||
title: "Post"
|
title: "Post"
|
||||||
}
|
},
|
||||||
|
{ type: "bytes", property: "filesize", title: "Filesize" }
|
||||||
];
|
];
|
||||||
|
|
||||||
const report = Report.create({
|
const report = Report.create({
|
||||||
@ -516,6 +518,15 @@ QUnit.test("computed labels", assert => {
|
|||||||
);
|
);
|
||||||
assert.equal(computedPostLabel.value, "This is the beginning of");
|
assert.equal(computedPostLabel.value, "This is the beginning of");
|
||||||
|
|
||||||
|
const filesizeLabel = computedLabels[6];
|
||||||
|
assert.equal(filesizeLabel.mainProperty, "filesize");
|
||||||
|
assert.equal(filesizeLabel.sortProperty, "filesize");
|
||||||
|
assert.equal(filesizeLabel.title, "Filesize");
|
||||||
|
assert.equal(filesizeLabel.type, "bytes");
|
||||||
|
const computedFilesizeLabel = filesizeLabel.compute(row);
|
||||||
|
assert.equal(computedFilesizeLabel.formatedValue, "569.0 KB");
|
||||||
|
assert.equal(computedFilesizeLabel.value, 582641);
|
||||||
|
|
||||||
// subfolder support
|
// subfolder support
|
||||||
Discourse.BaseUri = "/forum";
|
Discourse.BaseUri = "/forum";
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user