5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-11-26 08:06:23 +00:00

Merge branch 'blazer' into panel.sutty.nl

This commit is contained in:
f 2022-04-26 17:00:25 -03:00
commit 1b027574b4
5 changed files with 102 additions and 75 deletions

View file

@ -8,6 +8,10 @@ class StatsController < ApplicationController
before_action :authenticate_usuarie! before_action :authenticate_usuarie!
before_action :authorize_stats before_action :authorize_stats
breadcrumb -> { current_usuarie.email }, :edit_usuarie_registration_path
breadcrumb 'sites.index', :sites_path, match: :exact
breadcrumb -> { site.title }, -> { site_posts_path(site, locale: locale) }, match: :exact
EXTRA_OPTIONS = { EXTRA_OPTIONS = {
builds: {}, builds: {},
space_used: { bytes: true }, space_used: { bytes: true },
@ -20,7 +24,16 @@ class StatsController < ApplicationController
policy.script_src :self, :unsafe_inline policy.script_src :self, :unsafe_inline
end end
# Parámetros por defecto
#
# @return [Hash]
def default_url_options
{ interval: 'day', period_start: Date.today.beginning_of_year, period_end: Date.today }
end
def index def index
breadcrumb I18n.t('stats.index.title'), ''
@chart_params = { interval: interval } @chart_params = { interval: interval }
hostnames hostnames
last_stat last_stat
@ -30,9 +43,9 @@ class StatsController < ApplicationController
# Genera un gráfico de visitas por dominio asociado a este sitio # Genera un gráfico de visitas por dominio asociado a este sitio
def host def host
return unless stale? [last_stat, hostnames, interval] return unless stale? [last_stat, hostnames, interval, period]
stats = Rollup.where_dimensions(host: hostnames).multi_series('host', interval: interval).tap do |series| stats = rollup_scope.where_dimensions(host: hostnames).multi_series('host', interval: interval).tap do |series|
series.each do |serie| series.each do |serie|
serie[:name] = serie.dig(:dimensions, 'host') serie[:name] = serie.dig(:dimensions, 'host')
serie[:data].transform_values! do |value| serie[:data].transform_values! do |value|
@ -45,7 +58,7 @@ class StatsController < ApplicationController
end end
def resources def resources
return unless stale? [last_stat, interval, resource] return unless stale? [last_stat, interval, resource, period]
options = { options = {
interval: interval, interval: interval,
@ -54,14 +67,14 @@ class StatsController < ApplicationController
} }
} }
render json: Rollup.series(resource, **options) render json: rollup_scope.series(resource, **options)
end end
def uris def uris
return unless stale? [last_stat, hostnames, interval, normalized_urls] return unless stale? [last_stat, hostnames, interval, normalized_urls, period]
options = { host: hostnames, uri: normalized_paths } options = { host: hostnames, uri: normalized_paths }
stats = Rollup.where_dimensions(**options).multi_series('host|uri', interval: interval).tap do |series| stats = rollup_scope.where_dimensions(**options).multi_series('host|uri', interval: interval).tap do |series|
series.each do |serie| series.each do |serie|
serie[:name] = serie[:dimensions].slice('host', 'uri').values.join.sub('/index.html', '/') serie[:name] = serie[:dimensions].slice('host', 'uri').values.join.sub('/index.html', '/')
serie[:data].transform_values! do |value| serie[:data].transform_values! do |value|
@ -75,34 +88,43 @@ class StatsController < ApplicationController
private private
def rollup_scope
Rollup.where(time: period)
end
def last_stat def last_stat
@last_stat ||= Stat.last @last_stat ||= site.stats.last
end end
def authorize_stats def authorize_stats
@site = find_site authorize SiteStat.new(site)
authorize SiteStat.new(@site)
end end
# TODO: Eliminar cuando mergeemos referer-origin # TODO: Eliminar cuando mergeemos referer-origin
def hostnames def hostnames
@hostnames ||= [@site.hostname, @site.alternative_hostnames].flatten @hostnames ||= site.hostnames
end end
# Normalizar las URLs # Normalizar las URLs
# #
# @return [Array] # @return [Array]
def normalized_urls def normalized_urls
@normalized_urls ||= params.permit(:urls).try(:[], @normalized_urls ||=
:urls)&.split("\n")&.map(&:strip)&.select(&:present?)&.select do |uri| begin
uri.start_with? 'https://' urls = params.permit(:urls).try(:[], :urls)&.split("\n")&.map(&:strip)&.select(&:present?)&.select do |uri|
end&.map do |u| uri.start_with? 'https://'
# XXX: Eliminar end
# @see {https://0xacab.org/sutty/containers/nginx/-/merge_requests/1}
next u unless u.end_with? '/'
"#{u}index.html" urls ||= [site.url]
end&.uniq || [@site.url, @site.urls].flatten.uniq
urls.map do |u|
# XXX: Eliminar al deployear
# @see {https://0xacab.org/sutty/containers/nginx/-/merge_requests/1}
next u unless u.end_with? '/'
"#{u}index.html"
end.uniq
end
end end
def normalized_paths def normalized_paths
@ -140,14 +162,15 @@ class StatsController < ApplicationController
def interval def interval
@interval ||= begin @interval ||= begin
i = params[:interval]&.to_sym i = params[:interval]&.to_sym
Stat::INTERVALS.include?(i) ? i : :day Stat::INTERVALS.include?(i) ? i : Stat::INTERVALS.first
end end
end end
# @return [Symbol]
def resource def resource
@resource ||= begin @resource ||= begin
r = params[:resource].to_sym r = params[:resource].to_sym
Stat::RESOURCES.include?(r) ? r : :builds Stat::RESOURCES.include?(r) ? r : Stat::RESOURCES.first
end end
end end
@ -165,4 +188,15 @@ class StatsController < ApplicationController
def nodes def nodes
@nodes ||= ENV.fetch('NODES', 1).to_i @nodes ||= ENV.fetch('NODES', 1).to_i
end end
def period
@period ||= begin
p = params.permit(:period_start, :period_end)
p[:period_start]..p[:period_end]
end
end
def site
@site ||= find_site
end
end end

View file

@ -1,5 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
# Implementa rollups recursivos
module RecursiveRollup module RecursiveRollup
extend ActiveSupport::Concern extend ActiveSupport::Concern
@ -18,9 +19,8 @@ module RecursiveRollup
# @param :beginning [Time] # @param :beginning [Time]
# @return [Rollup] # @return [Rollup]
def recursive_rollup(name:, interval_previous:, interval:, dimensions:, beginning:, operation: :sum, new_name: nil) def recursive_rollup(name:, interval_previous:, interval:, dimensions:, beginning:, operation: :sum, new_name: nil)
Rollup.where(name: name, interval: interval_previous) Rollup.where(name: name, interval: interval_previous, dimensions: dimensions.to_json)
.where('time >= ?', beginning.try(:"beginning_of_#{interval}")) .where('time >= ?', beginning.try(:"beginning_of_#{interval}"))
.where_dimensions(**dimensions)
.group(*dimensions_to_jsonb_query(dimensions)) .group(*dimensions_to_jsonb_query(dimensions))
.rollup(new_name || name, interval: interval, update: true) do |rollup| .rollup(new_name || name, interval: interval, update: true) do |rollup|
rollup.try(operation, :value) rollup.try(operation, :value)

View file

@ -20,22 +20,30 @@ class UriCollectionJob < PeriodicJob
def perform(site_id:, once: true) def perform(site_id:, once: true)
@site = Site.find site_id @site = Site.find site_id
return unless File.directory? destination
# Recordar la última vez que se corrió la tarea # Recordar la última vez que se corrió la tarea
stat = site.stats.create! name: STAT_NAME stat = site.stats.create! name: STAT_NAME
name = 'host|uri'
beginning = beginning_of_interval beginning = beginning_of_interval
hostnames.each do |host| site.hostnames.each do |host|
break if stop? break if stop?
uris.each do |uri| uris.each do |uri|
break if stop? break if stop?
rollup_uri(uri, host, name, beginning) rollup('host|uri', beginning, host: host, uri: uri)
AccessLog.where(host: host, uri: uri).distinct(:http_referer).pluck(:http_referer).each do |http_referer|
rollup('host|uri|referer', beginning, host: host, uri: uri, http_referer: http_referer)
end
end end
rollup_host(host, name, beginning) rollup('host', beginning, host: host)
AccessLog.where(host: host).distinct(:http_referer).pluck(:http_referer).each do |http_referer|
rollup('host|referer', beginning, host: host, http_referer: http_referer)
end
end end
stat.touch stat.touch
@ -45,9 +53,14 @@ class UriCollectionJob < PeriodicJob
private private
def rollup_uri(uri, host, name, beginning) # Generar un rollup a partir de unas dimensiones que también sirven de
dimensions = { host: host, uri: uri } # filtro.
#
# @param :name [String]
# @param :beginning [Time]
# @param :dimensions [Hash]
# @return [nil]
def rollup(name, beginning, **dimensions)
AccessLog.where(**dimensions) AccessLog.where(**dimensions)
.where('created_at >= ?', beginning) .where('created_at >= ?', beginning)
.completed_requests .completed_requests
@ -69,28 +82,6 @@ class UriCollectionJob < PeriodicJob
end end
end end
def rollup_host(host, name, beginning)
dimensions = { host: host }
new_name = 'host'
recursive_rollup(name: name,
new_name: new_name,
interval_previous: starting_interval,
interval: starting_interval,
dimensions: dimensions,
beginning: beginning)
Stat::INTERVALS.reduce do |previous, current|
recursive_rollup(name: new_name,
interval_previous: previous,
interval: current,
dimensions: dimensions,
beginning: beginning)
current
end
end
def stat_name def stat_name
STAT_NAME STAT_NAME
end end
@ -102,26 +93,6 @@ class UriCollectionJob < PeriodicJob
@destination ||= site.deploys.find_by(type: 'DeployLocal').destination @destination ||= site.deploys.find_by(type: 'DeployLocal').destination
end end
# TODO: Cambiar al mergear origin-referer
#
# @return [Array]
def hostnames
@hostnames ||= site.deploys.map do |deploy|
case deploy
when DeployLocal
site.hostname
when DeployWww
deploy.fqdn
when DeployAlternativeDomain
deploy.hostname.dup.tap do |h|
h.replace(h.end_with?('.') ? h[0..-2] : "#{h}.#{Site.domain}")
end
when DeployHiddenService
deploy.onion
end
end.compact
end
# Recolecta todas las URIs menos imágenes # Recolecta todas las URIs menos imágenes
# #
# @return [Array] # @return [Array]

View file

@ -101,6 +101,26 @@ class Site < ApplicationRecord
"https://#{hostname}#{slash ? '/' : ''}" "https://#{hostname}#{slash ? '/' : ''}"
end end
# TODO: Cambiar al mergear origin-referer
#
# @return [Array]
def hostnames
@hostnames ||= deploys.map do |deploy|
case deploy
when DeployLocal
hostname
when DeployWww
deploy.fqdn
when DeployAlternativeDomain
deploy.hostname.dup.tap do |h|
h.replace(h.end_with?('.') ? h[0..-2] : "#{h}.#{Site.domain}")
end
when DeployHiddenService
deploy.onion
end
end.compact
end
# Obtiene los dominios alternativos # Obtiene los dominios alternativos
# #
# @return Array # @return Array
@ -123,7 +143,9 @@ class Site < ApplicationRecord
# #
# @return Array # @return Array
def urls(slash: true) def urls(slash: true)
alternative_urls(slash: slash) << url(slash: slash) @urls ||= hostnames.map do |h|
"https://#{h}#{slash ? '/' : ''}"
end
end end
def invitade?(usuarie) def invitade?(usuarie)

View file

@ -25,12 +25,12 @@
%input{ type: 'hidden', name: 'interval', value: @interval } %input{ type: 'hidden', name: 'interval', value: @interval }
.form-group .form-group
%label{ for: 'urls' }= t('.urls.label') %label{ for: 'urls' }= t('.urls.label')
%textarea#urls.form-control{ name: 'urls', autocomplete: 'on', required: true, rows: @normalized_urls.size, aria_describedby: 'help-urls' }= @normalized_urls.join("\n") %textarea#urls.form-control{ name: 'urls', autocomplete: 'on', required: true, rows: @normalized_urls.size + 1, aria_describedby: 'help-urls' }= @normalized_urls.join("\n")
%small#help-urls.feedback.form-text.text-muted= t('.urls.help') %small#help-urls.feedback.form-text.text-muted= t('.urls.help')
.form-group .form-group
%button.btn{ type: 'submit' }= t('.urls.submit') %button.btn{ type: 'submit' }= t('.urls.submit')
- if @normalized_urls.present? - if @normalized_urls.present?
= line_chart site_stats_uris_path(urls: params[:urls], **@chart_params), **@chart_options = line_chart site_stats_uris_path(urls: @normalized_urls, **@chart_params), **@chart_options
.mb-5 .mb-5
%h2= t('.resources.title') %h2= t('.resources.title')