diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index 07baaf1a..07be68c4 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -5,14 +5,68 @@ class StatsController < ApplicationController include Pundit before_action :authenticate_usuarie! + INTERVALS = %i[hour day week month].freeze + + # XXX: Permitir a Chart.js inyectar su propio CSS + content_security_policy only: :index do |policy| + policy.style_src :self, :unsafe_inline + policy.script_src :self, :unsafe_inline + end + def index @site = find_site authorize SiteStat.new(@site) - # Solo queremos el promedio de tiempo de compilación, no de - # instalación de dependencias. - stats = @site.build_stats.jekyll - @build_avg = stats.average(:seconds).to_f.round(2) - @build_max = stats.maximum(:seconds).to_f.round(2) + @chart_params = { interval: interval } + hostnames + end + + # Genera un gráfico de visitas por dominio asociado a este sitio + def host + @site = find_site + authorize SiteStat.new(@site) + + @stats = Rollup.where_dimensions(host: hostnames).multi_series('host', interval: interval).tap do |series| + series.each do |serie| + serie[:name] = serie.dig(:dimensions, 'host') + serie[:data].transform_values! do |value| + value * nodes + end + end + end + + render json: @stats + end + + private + + # TODO: Eliminar cuando mergeemos referer-origin + def hostnames + @hostnames ||= [@site.hostname, @site.alternative_hostnames].flatten + end + + # Obtiene y valida los intervalos + # + # @return [Symbol] + def interval + @interval ||= begin + i = params[:interval].to_sym + INTERVALS.include?(i) ? i : :day + end + end + + # Obtiene la cantidad de nodos de Sutty, para poder calcular la + # cantidad de visitas. + # + # Como repartimos las visitas por nodo rotando las IPs en el + # nameserver y los resolvedores de DNS eligen un nameserver + # aleatoriamente, la cantidad de visitas se reparte + # equitativamente. + # + # XXX: Remover cuando podamos centralizar los AccessLog + # + # @return [Integer] + def nodes + @nodes ||= ENV.fetch('NODES', 1).to_i end end diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index 6aa3a2e1..492ca736 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -18,6 +18,7 @@ import 'etc' import Rails from '@rails/ujs' import Turbolinks from 'turbolinks' import * as ActiveStorage from '@rails/activestorage' +import 'chartkick/chart.js' Rails.start() Turbolinks.start() diff --git a/app/policies/site_stat_policy.rb b/app/policies/site_stat_policy.rb index a797034c..d11be95d 100644 --- a/app/policies/site_stat_policy.rb +++ b/app/policies/site_stat_policy.rb @@ -12,4 +12,8 @@ class SiteStatPolicy def index? site_stat.site.usuarie? usuarie end + + def host? + index? + end end diff --git a/app/views/stats/index.haml b/app/views/stats/index.haml index f49cdd15..b5943690 100644 --- a/app/views/stats/index.haml +++ b/app/views/stats/index.haml @@ -1,17 +1,12 @@ -= render 'layouts/breadcrumb', - crumbs: [link_to(t('sites.index.title'), sites_path), - link_to(@site.name, site_path(@site)), t('.title')] - .row .col %h1= t('.title') %p.lead= t('.help') - %table.table.table-condensed - %tbody - %tr - %td= t('.build.average') - %td= distance_of_time_in_words_if_more_than_a_minute @build_avg - %tr - %td= t('.build.maximum') - %td= distance_of_time_in_words_if_more_than_a_minute @build_max + .mb-3 + - StatsController::INTERVALS.each do |interval| + = link_to t(".#{interval}"), site_stats_path(interval: interval), class: 'btn' + + .mb-3 + %h2= t('.host', count: @hostnames.size) + = line_chart site_stats_host_path(@chart_params), locale: 'es' diff --git a/config/locales/en.yml b/config/locales/en.yml index fc194eab..96250301 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -255,6 +255,15 @@ en: build: average: 'Average building time' maximum: 'Maximum building time' + hour: 'Hourly' + day: 'Daily' + week: 'Weekly' + month: 'Monthly' + year: 'Yearly' + host: + zero: 'Site visits' + one: 'Site visits' + other: 'Visits by site name' sites: donations: url: 'https://donaciones.sutty.nl/en/' diff --git a/config/locales/es.yml b/config/locales/es.yml index e8185391..7fcebcbe 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -260,6 +260,15 @@ es: build: average: 'Tiempo promedio de generación' maximum: 'Tiempo máximo de generación' + hour: 'Por hora' + day: 'Diarias' + week: 'Semanales' + month: 'Mensuales' + year: 'Anuales' + host: + zero: 'Visitas del sitio' + one: 'Visitas del sitio' + other: 'Visitas por nombre del sitio' sites: donations: url: 'https://donaciones.sutty.nl/' @@ -584,3 +593,7 @@ es: edit: 'Editando' usuaries: index: 'Usuaries' + day: 'Día' + week: 'Semana' + month: 'Mes' + year: 'Año' diff --git a/config/routes.rb b/config/routes.rb index 2c5f1c60..0af58080 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -75,5 +75,6 @@ Rails.application.routes.draw do post 'reorder_posts', to: 'sites#reorder_posts' resources :stats, only: [:index] + get :'stats/host', to: 'stats#host' end end