mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-26 03:01:14 +08:00
Same-IP user lookups now identify the target by user_id and ip_type rather than accepting a raw IP in params, so the IP is resolved server-side and never round-trips through clients that lack permission to see it. Additionally: - Hide the `suspicious_logins` report (list, bulk, show, CSV export and the security dashboard tile) from non-admin staff lacking `can_see_ip?`. - Hide the IP column and CSV export button on the screened emails page from staff lacking `can_see_ip?`. - Omit `ip_address` from `ScreenedUrlSerializer` for staff lacking `can_see_ip?`. - Require `can_see_ip?` (in addition to `can_see_emails?`) to export the `screened_email` entity. - Record the username (not the IP) in the staff-log context for "delete other accounts with same IP" when the acting user lacks `can_see_ip?`.
124 lines
3.4 KiB
Ruby
Vendored
124 lines
3.4 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
module Reports
|
|
class ListQuery
|
|
class FormattedReport
|
|
attr_reader :type, :name
|
|
|
|
def initialize(name)
|
|
@name = name
|
|
@type = name.to_s.gsub("report_", "")
|
|
end
|
|
|
|
def visible?(guardian:)
|
|
return false if Report.hidden?(type, guardian:)
|
|
|
|
if SiteSetting.reporting_improvements
|
|
return false if plugin_report? && plugin_disabled?
|
|
return false if Report::LEGACY_REPORTS.include?(type)
|
|
end
|
|
|
|
true
|
|
end
|
|
|
|
def to_h
|
|
result = {
|
|
type:,
|
|
title:,
|
|
description:,
|
|
description_link: I18n.t("reports.#{type}.description_link", default: "").presence,
|
|
}
|
|
|
|
if SiteSetting.reporting_improvements && plugin_report?
|
|
result[:plugin] = plugin_name
|
|
result[:plugin_display_name] = plugin_display_name
|
|
end
|
|
|
|
result
|
|
end
|
|
|
|
private
|
|
|
|
# HACK: We need to show a different label and description for some
|
|
# old reports while people are still relying on them, that lets us
|
|
# point toward the new 'Site traffic' report as well. Not ideal,
|
|
# but apart from duplicating the report there's not a nicer way to do this.
|
|
def title
|
|
return I18n.t("reports.#{type}.title_legacy") if legacy?
|
|
I18n.t("reports.#{type}.title")
|
|
end
|
|
|
|
def description
|
|
return I18n.t("reports.#{type}.description_legacy") if legacy?
|
|
I18n.t("reports.#{type}.description", default: "").presence
|
|
end
|
|
|
|
def legacy?
|
|
SiteSetting.use_legacy_pageviews &&
|
|
type.in?(%w[consolidated_page_views consolidated_page_views_browser_detection])
|
|
end
|
|
|
|
def plugin_name
|
|
return @plugin_name if defined?(@plugin_name)
|
|
|
|
@plugin_name = resolve_plugin_name
|
|
end
|
|
|
|
def resolve_plugin_name
|
|
return unless Report.singleton_class.method_defined?(@name)
|
|
|
|
source_path = Report.method(@name).source_location.first
|
|
return unless source_path&.include?("/plugins/")
|
|
|
|
# Extract plugin name from path like /plugins/discourse-ai/...
|
|
match = source_path.match(%r{/plugins/([^/]+)/})
|
|
match[1] if match
|
|
rescue NameError
|
|
nil
|
|
end
|
|
|
|
def plugin_instance
|
|
return @plugin_instance if defined?(@plugin_instance)
|
|
@plugin_instance = plugin_name && Discourse.plugins_by_name[plugin_name]
|
|
end
|
|
|
|
def plugin_display_name
|
|
plugin_instance&.humanized_name
|
|
end
|
|
|
|
def plugin_report?
|
|
plugin_name.present?
|
|
end
|
|
|
|
def plugin_disabled?
|
|
return true unless plugin_instance
|
|
!plugin_instance.enabled?
|
|
end
|
|
end
|
|
|
|
def self.call(guardian:)
|
|
page_view_req_report_methods =
|
|
["page_view_total_reqs"] +
|
|
ApplicationRequest
|
|
.req_types
|
|
.keys
|
|
.select { |r| r =~ /\Apage_view_/ && r !~ /mobile/ && r !~ /beacon/ }
|
|
.map { |r| r + "_reqs" }
|
|
|
|
if !SiteSetting.use_legacy_pageviews
|
|
page_view_req_report_methods << "page_view_legacy_total_reqs"
|
|
end
|
|
|
|
reports_methods =
|
|
page_view_req_report_methods +
|
|
Report.singleton_methods.grep(/\Areport_(?!about|storage_stats)/)
|
|
|
|
reports_methods
|
|
.filter_map do |report_name|
|
|
report = Reports::ListQuery::FormattedReport.new(report_name)
|
|
report.to_h if report.visible?(guardian:)
|
|
end
|
|
.sort_by { |report| report[:title] }
|
|
end
|
|
end
|
|
end
|