Merge pull request #5503 from consuldemocracy/admin_stats_without_ahoy
Improve stats graphs in admin section
This commit is contained in:
@@ -5,14 +5,12 @@
|
||||
var buildGraph;
|
||||
|
||||
buildGraph = function(el) {
|
||||
var conf, url;
|
||||
url = $(el).data("graph");
|
||||
var conf;
|
||||
conf = {
|
||||
bindto: el,
|
||||
data: {
|
||||
x: "x",
|
||||
url: url,
|
||||
mimeType: "json"
|
||||
json: $(el).data("graph")
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
|
||||
11
app/assets/stylesheets/admin/stats/event_links.scss
Normal file
11
app/assets/stylesheets/admin/stats/event_links.scss
Normal file
@@ -0,0 +1,11 @@
|
||||
.stats-event-links {
|
||||
@include header-font-size(h3);
|
||||
font-weight: bold;
|
||||
list-style-type: none;
|
||||
margin-#{$global-left}: 0;
|
||||
margin-top: $line-height;
|
||||
|
||||
* + * {
|
||||
margin-top: $line-height;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ class Admin::Settings::FeaturesTabComponent < ApplicationComponent
|
||||
feature.google_login
|
||||
feature.twitter_login
|
||||
feature.wordpress_login
|
||||
feature.public_stats
|
||||
feature.signature_sheets
|
||||
feature.user.recommendations
|
||||
feature.user.recommendations_on_debates
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "admin/stats/graph", name: "user_supported_budgets", event: "", count: user_count %>
|
||||
<%= render Admin::Stats::ChartComponent.new(chart) %>
|
||||
|
||||
<table class="investment-projects-summary user-count-by-heading">
|
||||
<thead>
|
||||
|
||||
@@ -28,4 +28,8 @@ class Admin::Stats::BudgetSupportingComponent < ApplicationComponent
|
||||
[heading, headings_stats[heading.id][:total_participants_support_phase]]
|
||||
end
|
||||
end
|
||||
|
||||
def chart
|
||||
@chart ||= Ahoy::Chart.new("budget_investment_supported")
|
||||
end
|
||||
end
|
||||
|
||||
4
app/components/admin/stats/chart_component.html.erb
Normal file
4
app/components/admin/stats/chart_component.html.erb
Normal file
@@ -0,0 +1,4 @@
|
||||
<div id="graph" class="small-12 column">
|
||||
<h2><%= title %></h2>
|
||||
<%= chart_tag %>
|
||||
</div>
|
||||
25
app/components/admin/stats/chart_component.rb
Normal file
25
app/components/admin/stats/chart_component.rb
Normal file
@@ -0,0 +1,25 @@
|
||||
class Admin::Stats::ChartComponent < ApplicationComponent
|
||||
attr_reader :chart
|
||||
|
||||
def initialize(chart)
|
||||
@chart = chart
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def count
|
||||
chart.count
|
||||
end
|
||||
|
||||
def event
|
||||
chart.event_name
|
||||
end
|
||||
|
||||
def chart_tag
|
||||
tag.div("data-graph": chart.data_points.to_json)
|
||||
end
|
||||
|
||||
def title
|
||||
"#{chart.title} (#{count})"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
<%= link_list(*links, class: "stats-event-links") %>
|
||||
20
app/components/admin/stats/event_links_component.rb
Normal file
20
app/components/admin/stats/event_links_component.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
class Admin::Stats::EventLinksComponent < ApplicationComponent
|
||||
attr_reader :event_names
|
||||
use_helpers :link_list
|
||||
|
||||
def initialize(event_names)
|
||||
@event_names = event_names
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def link_text(event)
|
||||
Ahoy::Chart.new(event).title
|
||||
end
|
||||
|
||||
def links
|
||||
event_names.map do |event|
|
||||
[link_text(event), graph_admin_stats_path(event: event)]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
<div class="stats-global-chart">
|
||||
<h2><%= title %></h2>
|
||||
<%= chart_tag %>
|
||||
<%= render Admin::Stats::EventLinksComponent.new(event_names) %>
|
||||
</div>
|
||||
19
app/components/admin/stats/global_chart_component.rb
Normal file
19
app/components/admin/stats/global_chart_component.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
class Admin::Stats::GlobalChartComponent < ApplicationComponent
|
||||
private
|
||||
|
||||
def event_names
|
||||
Ahoy::Chart.active_event_names
|
||||
end
|
||||
|
||||
def chart_tag
|
||||
tag.div("data-graph": data_points.to_json)
|
||||
end
|
||||
|
||||
def data_points
|
||||
Ahoy::Chart.active_events_data_points
|
||||
end
|
||||
|
||||
def title
|
||||
t("admin.stats.graph.title")
|
||||
end
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
<%= back_link_to %>
|
||||
<%= back_link_to admin_stats_path %>
|
||||
|
||||
<%= header %>
|
||||
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
class Admin::Api::StatsController < Admin::Api::BaseController
|
||||
def show
|
||||
if params[:event].blank? &&
|
||||
params[:visits].blank? &&
|
||||
params[:budget_investments].blank? &&
|
||||
params[:user_supported_budgets].blank?
|
||||
return render json: {}, status: :bad_request
|
||||
end
|
||||
|
||||
ds = Ahoy::DataSource.new
|
||||
|
||||
if params[:event].present?
|
||||
ds.add params[:event].titleize, Ahoy::Event.where(name: params[:event]).group_by_day(:time).count
|
||||
end
|
||||
|
||||
if params[:visits].present?
|
||||
ds.add "Visits", Visit.group_by_day(:started_at).count
|
||||
end
|
||||
|
||||
if params[:budget_investments].present?
|
||||
ds.add "Budget Investments", Budget::Investment.group_by_day(:created_at).count
|
||||
end
|
||||
|
||||
if params[:user_supported_budgets].present?
|
||||
ds.add "User supported budgets",
|
||||
Vote.where(votable_type: "Budget::Investment").group_by_day(:updated_at).count
|
||||
end
|
||||
render json: ds.build
|
||||
end
|
||||
end
|
||||
@@ -1,7 +1,5 @@
|
||||
class Admin::StatsController < Admin::BaseController
|
||||
def show
|
||||
@event_types = Ahoy::Event.distinct.order(:name).pluck(:name)
|
||||
|
||||
@visits = Visit.count
|
||||
@debates = Debate.with_hidden.count
|
||||
@proposals = Proposal.with_hidden.count
|
||||
@@ -30,14 +28,7 @@ class Admin::StatsController < Admin::BaseController
|
||||
end
|
||||
|
||||
def graph
|
||||
@name = params[:id]
|
||||
@event = params[:event]
|
||||
|
||||
if params[:event]
|
||||
@count = Ahoy::Event.where(name: params[:event]).count
|
||||
else
|
||||
@count = params[:count]
|
||||
end
|
||||
@chart = Ahoy::Chart.new(params[:event])
|
||||
end
|
||||
|
||||
def proposal_notifications
|
||||
|
||||
@@ -11,7 +11,6 @@ class ApplicationController < ActionController::Base
|
||||
|
||||
before_action :ensure_signup_complete
|
||||
around_action :switch_locale
|
||||
before_action :track_email_campaign
|
||||
before_action :set_return_url
|
||||
|
||||
check_authorization unless: :devise_controller?
|
||||
@@ -91,13 +90,6 @@ class ApplicationController < ActionController::Base
|
||||
end
|
||||
end
|
||||
|
||||
def track_email_campaign
|
||||
if params[:track_id]
|
||||
campaign = Campaign.find_by(track_id: params[:track_id])
|
||||
ahoy.track campaign.name if campaign.present?
|
||||
end
|
||||
end
|
||||
|
||||
def set_return_url
|
||||
if request.get? && !devise_controller? && is_navigational_format?
|
||||
store_location_for(:user, request.fullpath)
|
||||
|
||||
@@ -44,21 +44,6 @@ module CommentableActions
|
||||
@resources = @search_terms.present? ? resource_relation.search(@search_terms) : nil
|
||||
end
|
||||
|
||||
def create
|
||||
@resource = resource_model.new(strong_params)
|
||||
@resource.author = current_user
|
||||
|
||||
if @resource.save
|
||||
track_event
|
||||
redirect_path = url_for(controller: controller_name, action: :show, id: @resource.id)
|
||||
redirect_to redirect_path, notice: t("flash.actions.create.#{resource_name.underscore}")
|
||||
else
|
||||
load_geozones
|
||||
set_resource_instance
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
@@ -74,10 +59,6 @@ module CommentableActions
|
||||
|
||||
private
|
||||
|
||||
def track_event
|
||||
ahoy.track :"#{resource_name}_created", "#{resource_name}_id": resource.id
|
||||
end
|
||||
|
||||
def tag_cloud
|
||||
TagCloud.new(resource_model, params[:search])
|
||||
end
|
||||
|
||||
@@ -19,6 +19,17 @@ class DebatesController < ApplicationController
|
||||
helper_method :resource_model, :resource_name
|
||||
respond_to :html, :js
|
||||
|
||||
def create
|
||||
@debate = Debate.new(debate_params)
|
||||
@debate.author = current_user
|
||||
|
||||
if @debate.save
|
||||
redirect_to debate_path(@debate), notice: t("flash.actions.create.debate")
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def index_customization
|
||||
@featured_debates = @debates.featured
|
||||
end
|
||||
|
||||
@@ -51,7 +51,6 @@ class Legislation::AnnotationsController < Legislation::BaseController
|
||||
@annotation = @draft_version.annotations.new(annotation_params)
|
||||
@annotation.author = current_user
|
||||
if @annotation.save
|
||||
track_event
|
||||
render json: @annotation.to_json
|
||||
else
|
||||
render json: @annotation.errors.full_messages, status: :unprocessable_entity
|
||||
@@ -100,12 +99,6 @@ class Legislation::AnnotationsController < Legislation::BaseController
|
||||
[:quote, :text, ranges: [:start, :startOffset, :end, :endOffset]]
|
||||
end
|
||||
|
||||
def track_event
|
||||
ahoy.track :legislation_annotation_created,
|
||||
legislation_annotation_id: @annotation.id,
|
||||
legislation_draft_version_id: @draft_version.id
|
||||
end
|
||||
|
||||
def convert_ranges_parameters
|
||||
annotation = params[:legislation_annotation]
|
||||
if annotation && annotation[:ranges] && annotation[:ranges].is_a?(String)
|
||||
|
||||
@@ -12,7 +12,6 @@ class Legislation::AnswersController < Legislation::BaseController
|
||||
if @process.debate_phase.open?
|
||||
@answer.user = current_user
|
||||
@answer.save!
|
||||
track_event
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.html { redirect_to legislation_process_question_path(@process, @question) }
|
||||
@@ -35,11 +34,4 @@ class Legislation::AnswersController < Legislation::BaseController
|
||||
def allowed_params
|
||||
[:legislation_question_option_id]
|
||||
end
|
||||
|
||||
def track_event
|
||||
ahoy.track :legislation_answer_created,
|
||||
legislation_answer_id: @answer.id,
|
||||
legislation_question_option_id: @answer.legislation_question_option_id,
|
||||
legislation_question_id: @answer.legislation_question_id
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,7 +17,6 @@ class Management::ProposalsController < Management::BaseController
|
||||
published_at: Time.current))
|
||||
|
||||
if @resource.save
|
||||
track_event
|
||||
redirect_path = url_for(controller: controller_name, action: :show, id: @resource.id)
|
||||
redirect_to redirect_path, notice: t("flash.actions.create.#{resource_name.underscore}")
|
||||
else
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
class StatsController < ApplicationController
|
||||
include FeatureFlags
|
||||
|
||||
feature_flag :public_stats
|
||||
|
||||
skip_authorization_check
|
||||
|
||||
def index
|
||||
@visits = daily_cache("visits") { Visit.count }
|
||||
@debates = daily_cache("debates") { Debate.with_hidden.count }
|
||||
@proposals = daily_cache("proposals") { Proposal.with_hidden.count }
|
||||
@comments = daily_cache("comments") { Comment.not_valuations.with_hidden.count }
|
||||
|
||||
@debate_votes = daily_cache("debate_votes") { Vote.count_for("Debate") }
|
||||
@proposal_votes = daily_cache("proposal_votes") { Vote.count_for("Proposal") }
|
||||
@comment_votes = daily_cache("comment_votes") { Vote.count_for("Comment") }
|
||||
@investment_votes = daily_cache("budget_investment_votes") { Vote.count_for("Budget::Investment") }
|
||||
@votes = daily_cache("votes") { Vote.count }
|
||||
|
||||
@verified_users = daily_cache("verified_users") { User.with_hidden.level_two_or_three_verified.count }
|
||||
@unverified_users = daily_cache("unverified_users") { User.with_hidden.unverified.count }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def daily_cache(key, &)
|
||||
Rails.cache.fetch("public_stats/#{Time.current.strftime("%Y-%m-%d")}/#{key}", &)
|
||||
end
|
||||
end
|
||||
@@ -28,7 +28,6 @@ class Verification::SmsController < ApplicationController
|
||||
@sms = Verification::Sms.new(sms_params.merge(user: current_user))
|
||||
if @sms.verified?
|
||||
current_user.update!(confirmed_phone: current_user.unconfirmed_phone)
|
||||
ahoy.track(:level_2_user, user_id: current_user.id) rescue nil
|
||||
|
||||
if VerifiedUser.phone?(current_user)
|
||||
current_user.update(verified_at: Time.current)
|
||||
|
||||
@@ -1,34 +1,4 @@
|
||||
module StatsHelper
|
||||
def chart_tag(opt = {})
|
||||
opt[:data] ||= {}
|
||||
opt[:data][:graph] = admin_api_stats_path(chart_data(opt))
|
||||
tag.div(**opt)
|
||||
end
|
||||
|
||||
def chart_data(opt = {})
|
||||
data = nil
|
||||
if opt[:id].present?
|
||||
data = { opt[:id] => true }
|
||||
elsif opt[:event].present?
|
||||
data = { event: opt[:event] }
|
||||
end
|
||||
data
|
||||
end
|
||||
|
||||
def graph_link_text(event)
|
||||
text = t("admin.stats.graph.#{event}")
|
||||
if text.to_s.match(/translation missing/)
|
||||
text = event
|
||||
end
|
||||
text
|
||||
end
|
||||
|
||||
def budget_investments_chart_tag(opt = {})
|
||||
opt[:data] ||= {}
|
||||
opt[:data][:graph] = admin_api_stats_path(budget_investments: true)
|
||||
tag.div(**opt)
|
||||
end
|
||||
|
||||
def number_to_stats_percentage(number, options = {})
|
||||
number_to_percentage(number, { strip_insignificant_zeros: true, precision: 2 }.merge(options))
|
||||
end
|
||||
|
||||
77
app/models/ahoy/chart.rb
Normal file
77
app/models/ahoy/chart.rb
Normal file
@@ -0,0 +1,77 @@
|
||||
module Ahoy
|
||||
class Chart
|
||||
attr_reader :event_name
|
||||
delegate :count, to: :records
|
||||
delegate :t, to: "ApplicationController.helpers"
|
||||
|
||||
def initialize(event_name)
|
||||
@event_name = event_name
|
||||
end
|
||||
|
||||
def self.active_event_names
|
||||
event_names_with_collections.select { |name, collection| collection.any? }.keys.sort_by do |event_name|
|
||||
new(event_name).title
|
||||
end
|
||||
end
|
||||
|
||||
def self.event_names_with_collections
|
||||
{
|
||||
budget_investment_created: Budget::Investment.with_hidden,
|
||||
debate_created: Debate.with_hidden,
|
||||
legislation_annotation_created: Legislation::Annotation.with_hidden,
|
||||
legislation_answer_created: Legislation::Answer.with_hidden,
|
||||
level_3_user: User.with_hidden.level_three_verified,
|
||||
proposal_created: Proposal.with_hidden
|
||||
}
|
||||
end
|
||||
|
||||
def self.active_events_data_points
|
||||
Ahoy::DataSource.build do |data_source|
|
||||
active_event_names.map { |event_name| new(event_name) }.each do |chart|
|
||||
data_source.add chart.title, chart.data
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def data_points
|
||||
Ahoy::DataSource.build do |data_source|
|
||||
data_source.add title, data
|
||||
end
|
||||
end
|
||||
|
||||
def title
|
||||
t("admin.stats.graph.#{event_name}")
|
||||
end
|
||||
|
||||
def data
|
||||
records_by_day.count
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def records
|
||||
case event_name.to_sym
|
||||
when :budget_investment_supported
|
||||
Vote.where(votable_type: "Budget::Investment")
|
||||
when :visits
|
||||
Visit.all
|
||||
else
|
||||
self.class.event_names_with_collections[event_name.to_sym]
|
||||
end
|
||||
end
|
||||
|
||||
def records_by_day
|
||||
raise "Unknown event #{event_name}" unless records.respond_to?(:group_by_day)
|
||||
|
||||
records.group_by_day(date_field)
|
||||
end
|
||||
|
||||
def date_field
|
||||
if event_name.to_sym == :level_3_user
|
||||
:verified_at
|
||||
else
|
||||
:created_at
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -4,24 +4,28 @@
|
||||
|
||||
module Ahoy
|
||||
class DataSource
|
||||
def self.build(&block)
|
||||
new.tap { |data_source| block.call(data_source) }.build
|
||||
end
|
||||
|
||||
# Adds a collection with the datasource
|
||||
# Name is the name of the collection and will be showed in the
|
||||
# chart
|
||||
def add(name, collection)
|
||||
collections.push data: collection, name: name
|
||||
collection.each_key { |key| add_key key }
|
||||
dates.merge(collection.keys)
|
||||
end
|
||||
|
||||
def build
|
||||
data = { x: [] }
|
||||
shared_keys.each do |k|
|
||||
dates.sort.each do |date|
|
||||
# Add the key with a valid date format
|
||||
data[:x].push k.strftime("%Y-%m-%d")
|
||||
data[:x].push date.strftime("%Y-%m-%d")
|
||||
|
||||
# Add the value for each column, or 0 if not present
|
||||
collections.each do |col|
|
||||
data[col[:name]] ||= []
|
||||
count = col[:data][k] || 0
|
||||
count = col[:data][date] || 0
|
||||
data[col[:name]].push count
|
||||
end
|
||||
end
|
||||
@@ -35,12 +39,8 @@ module Ahoy
|
||||
@collections ||= []
|
||||
end
|
||||
|
||||
def shared_keys
|
||||
@shared_keys ||= []
|
||||
end
|
||||
|
||||
def add_key(key)
|
||||
shared_keys.push(key) unless shared_keys.include? key
|
||||
def dates
|
||||
@dates ||= Set.new
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
class Campaign < ApplicationRecord
|
||||
end
|
||||
@@ -70,7 +70,6 @@ class Setting < ApplicationRecord
|
||||
"feature.google_login": true,
|
||||
"feature.twitter_login": true,
|
||||
"feature.wordpress_login": false,
|
||||
"feature.public_stats": true,
|
||||
"feature.signature_sheets": true,
|
||||
"feature.user.recommendations": true,
|
||||
"feature.user.recommendations_on_debates": true,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
class Visit < ApplicationRecord
|
||||
alias_attribute :created_at, :started_at
|
||||
has_many :ahoy_events, class_name: "Ahoy::Event"
|
||||
belongs_to :user
|
||||
end
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
<div id="graph" class="small-12 column">
|
||||
<h2><%= t "admin.stats.graph.#{name || event}" %> (<%= count %>)</h2>
|
||||
<%= chart_tag id: name, event: event %>
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
<%= back_link_to %>
|
||||
<%= back_link_to admin_stats_path %>
|
||||
|
||||
<h2><%= t("admin.stats.direct_messages.title") %></h2>
|
||||
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
|
||||
<%= back_link_to admin_stats_path %>
|
||||
|
||||
<%= render "graph", name: @name, event: @event, count: @count %>
|
||||
<%= render Admin::Stats::ChartComponent.new(@chart) %>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<%= back_link_to %>
|
||||
<%= back_link_to admin_stats_path %>
|
||||
|
||||
<h2 id="top"><%= t("admin.stats.polls.title") %></h2>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<%= back_link_to %>
|
||||
<%= back_link_to admin_stats_path %>
|
||||
|
||||
<h2><%= t("admin.stats.proposal_notifications.title") %></h2>
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
<% content_for :head do %>
|
||||
<%= javascript_include_tag "stat_graphs", "data-turbolinks-track" => "reload" %>
|
||||
<% end %>
|
||||
|
||||
<div id="stats" class="stats">
|
||||
<div class="row">
|
||||
<div class="small-12 column">
|
||||
@@ -24,7 +28,7 @@
|
||||
<div class="small-12 medium-3 column">
|
||||
<p class="featured">
|
||||
<%= link_to t("admin.stats.show.summary.visits"),
|
||||
graph_admin_stats_path(id: "visits", count: @visits) %> <br>
|
||||
graph_admin_stats_path(event: "visits") %> <br>
|
||||
<span class="number"><%= number_with_delimiter(@visits) %></span>
|
||||
</p>
|
||||
<p>
|
||||
@@ -110,21 +114,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="small-12 column">
|
||||
<% @event_types.each do |event| %>
|
||||
<h3>
|
||||
<%= link_to graph_link_text(event),
|
||||
graph_admin_stats_path(event: event) %>
|
||||
</h3>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if feature?(:budgets) %>
|
||||
<div class="small-12 column">
|
||||
<h2><%= t "admin.stats.show.budgets_title" %></h2>
|
||||
<%= budget_investments_chart_tag id: "budget_investments" %>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= render Admin::Stats::GlobalChartComponent.new %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
<div class="stats row-full">
|
||||
<div class="row">
|
||||
<div class="small-12 column">
|
||||
<h1><%= t "admin.stats.show.stats_title" %></h1>
|
||||
|
||||
<div class="row stats-numbers">
|
||||
<div class="small-12 medium-4 column">
|
||||
<p class="featured">
|
||||
<%= t "stats.index.visits" %><br>
|
||||
<span class="number"><%= number_with_delimiter(@visits) %></span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<%= t "stats.index.debates" %><br>
|
||||
<span class="number"><%= number_with_delimiter(@debates) %></span>
|
||||
</p>
|
||||
<p>
|
||||
<%= t "stats.index.proposals" %><br>
|
||||
<span class="number"><%= number_with_delimiter(@proposals) %></span>
|
||||
</p>
|
||||
<p>
|
||||
<%= t "stats.index.comments" %><br>
|
||||
<span class="number"><%= number_with_delimiter(@comments) %></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-4 column">
|
||||
<p class="featured">
|
||||
<%= t "stats.index.proposal_votes" %><br>
|
||||
<span class="number"><%= number_with_delimiter(@proposal_votes) %><br></span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<%= t "stats.index.debate_votes" %><br>
|
||||
<span class="number"><%= number_with_delimiter(@debate_votes) %></span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<%= t "stats.index.comment_votes" %><br>
|
||||
<span class="number"><%= number_with_delimiter(@comment_votes) %></span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<%= t "stats.index.votes" %><br>
|
||||
<span class="number"><%= number_with_delimiter(@votes) %></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-4 column">
|
||||
<p class="featured">
|
||||
<%= t "stats.index.verified_users" %><br>
|
||||
<span class="number"><%= number_with_delimiter(@verified_users) %></span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<%= t "stats.index.unverified_users" %><br>
|
||||
<span class="number"><%= number_with_delimiter(@unverified_users) %></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"<%= t("stats.index.visits") %>" : "<%= number_with_delimiter(@visits) %>",
|
||||
"<%= t("stats.index.debates") %>" : "<%= number_with_delimiter(@debates) %>",
|
||||
"<%= t("stats.index.proposals") %>" : "<%= number_with_delimiter(@proposals) %>",
|
||||
"<%= t("stats.index.comments") %>" : "<%= number_with_delimiter(@comments) %>",
|
||||
"<%= t("stats.index.proposal_votes") %>" : "<%= number_with_delimiter(@proposal_votes) %>",
|
||||
"<%= t("stats.index.debate_votes") %>" : "<%= number_with_delimiter(@debate_votes) %>",
|
||||
"<%= t("stats.index.comment_votes") %>" : "<%= number_with_delimiter(@comment_votes) %>",
|
||||
"<%= t("stats.index.votes") %>" : "<%= number_with_delimiter(@votes) %>",
|
||||
"<%= t("stats.index.verified_users") %>" : "<%= number_with_delimiter(@verified_users) %>",
|
||||
"<%= t("stats.index.unverified_users") %>" : "<%= number_with_delimiter(@unverified_users) %>"
|
||||
}
|
||||
@@ -1480,7 +1480,6 @@ en:
|
||||
verified_users_who_didnt_vote_proposals: Verified users who didn't votes proposals
|
||||
visits: Visits
|
||||
votes: Total votes
|
||||
budgets_title: Participatory budgeting
|
||||
participatory_budgets: Participatory Budgets
|
||||
direct_messages: Direct messages
|
||||
proposal_notifications: Proposal notifications
|
||||
@@ -1488,10 +1487,15 @@ en:
|
||||
polls: Polls
|
||||
sdg: SDG
|
||||
graph:
|
||||
debate_created: Debates
|
||||
visit: Visits
|
||||
level_2_user: Level 2 users
|
||||
proposal_created: Citizen proposals
|
||||
budget_investment_created: Budget investments created
|
||||
budget_investment_supported: Budget investments supported
|
||||
debate_created: Debates created
|
||||
legislation_annotation_created: Legislation annotations created
|
||||
legislation_answer_created: Legislation answers created
|
||||
level_3_user: Level 3 users verified
|
||||
proposal_created: Citizen proposals created
|
||||
title: Graphs
|
||||
visits: Visits
|
||||
budgets:
|
||||
no_data_before_balloting_phase: "There isn't any data to show before the balloting phase."
|
||||
title: "Participatory Budgets - Participation stats"
|
||||
|
||||
@@ -761,18 +761,6 @@ en:
|
||||
youtube: "%{org} YouTube"
|
||||
telegram: "%{org} Telegram"
|
||||
instagram: "%{org} Instagram"
|
||||
stats:
|
||||
index:
|
||||
visits: Visits
|
||||
debates: Debates
|
||||
proposals: Proposals
|
||||
comments: Comments
|
||||
proposal_votes: Votes on proposals
|
||||
debate_votes: Votes on debates
|
||||
comment_votes: Votes on comments
|
||||
votes: Total votes
|
||||
verified_users: Verified users
|
||||
unverified_users: Unverified users
|
||||
unauthorized:
|
||||
default: You do not have permission to access this page.
|
||||
manage:
|
||||
|
||||
@@ -116,8 +116,6 @@ en:
|
||||
allow_attached_documents_description: "Allows users to upload documents when creating proposals and investment projects from Participatory Budgets"
|
||||
guides: "Guides to create proposals or investment projects"
|
||||
guides_description: "Displays a guide to differences between proposals and investment projects if there is an active participatory budget"
|
||||
public_stats: "Public stats"
|
||||
public_stats_description: "Display public stats in the Administration panel"
|
||||
help_page: "Help page"
|
||||
help_page_description: 'Displays a Help menu that contains a page with an info section about each enabled feature. Also custom pages and menus can be created in the "Custom pages" and "Custom content blocks" sections'
|
||||
remote_translations: "Remote translation"
|
||||
|
||||
@@ -1480,7 +1480,6 @@ es:
|
||||
verified_users_who_didnt_vote_proposals: Usuarios verificados que no han votado propuestas
|
||||
visits: Visitas
|
||||
votes: Votos
|
||||
budgets_title: Presupuestos participativos
|
||||
participatory_budgets: Presupuestos Participativos
|
||||
direct_messages: Mensajes directos
|
||||
proposal_notifications: Notificaciones de propuestas
|
||||
@@ -1488,10 +1487,15 @@ es:
|
||||
polls: Votaciones
|
||||
sdg: ODS
|
||||
graph:
|
||||
debate_created: Debates
|
||||
budget_investment_created: Proyectos de gasto creados
|
||||
budget_investment_supported: Proyectos de gasto apoyados
|
||||
debate_created: Debates creados
|
||||
legislation_annotation_created: Anotaciones creadas
|
||||
legislation_answer_created: Repuestas de legislación colaborativa creadas
|
||||
level_3_user: Usuarios de nivel 3 verificados
|
||||
proposal_created: Propuestas Ciudadanas creadas
|
||||
title: Gráficos
|
||||
visit: Visitas
|
||||
level_2_user: Usuarios nivel 2
|
||||
proposal_created: Propuestas Ciudadanas
|
||||
budgets:
|
||||
no_data_before_balloting_phase: "No hay datos que mostrar hasta que la fase de votación no esté abierta."
|
||||
title: "Presupuestos participativos - Estadisticas de participación"
|
||||
|
||||
@@ -761,18 +761,6 @@ es:
|
||||
youtube: "YouTube de %{org}"
|
||||
telegram: "Telegram de %{org}"
|
||||
instagram: "Instagram de %{org}"
|
||||
stats:
|
||||
index:
|
||||
visits: Visitas
|
||||
debates: Debates
|
||||
proposals: Propuestas ciudadanas
|
||||
comments: Comentarios
|
||||
proposal_votes: Votos en propuestas
|
||||
debate_votes: Votos en debates
|
||||
comment_votes: Votos en comentarios
|
||||
votes: Votos
|
||||
verified_users: Usuarios verificados
|
||||
unverified_users: Usuarios sin verificar
|
||||
unauthorized:
|
||||
default: No tienes permiso para acceder a esta página.
|
||||
manage:
|
||||
|
||||
@@ -116,8 +116,6 @@ es:
|
||||
allow_attached_documents_description: "Permite que los usuarios suban documentos al crear propuestas y proyectos de gasto de los Presupuestos participativos"
|
||||
guides: "Guías para crear propuestas o proyectos de inversión"
|
||||
guides_description: "Muestra una guía de diferencias entre las propuestas y los proyectos de gasto si hay un presupuesto participativo activo"
|
||||
public_stats: "Estadísticas públicas"
|
||||
public_stats_description: "Muestra las estadísticas públicas en el panel de Administración"
|
||||
help_page: "Página de ayuda"
|
||||
help_page_description: 'Muestra un menú Ayuda que contiene una página con una sección de información sobre cada funcionalidad habilitada. También se pueden crear páginas y menús personalizados en las secciones "Personalizar páginas" y "Personalizar bloques"'
|
||||
remote_translations: "Traducciones remotas"
|
||||
|
||||
@@ -32,7 +32,6 @@ Rails.application.routes.draw do
|
||||
get "/consul.json", to: "installation#details"
|
||||
get "robots.txt", to: "robots#index"
|
||||
|
||||
resources :stats, only: [:index]
|
||||
resources :images, only: [:destroy]
|
||||
resources :documents, only: [:destroy]
|
||||
resources :follows, only: [:create, :destroy]
|
||||
|
||||
@@ -241,10 +241,6 @@ namespace :admin do
|
||||
end
|
||||
end
|
||||
|
||||
namespace :api do
|
||||
resource :stats, only: :show
|
||||
end
|
||||
|
||||
resources :geozones, only: [:index, :new, :create, :edit, :update, :destroy]
|
||||
|
||||
namespace :site_customization do
|
||||
|
||||
13
spec/components/admin/stats/chart_component_spec.rb
Normal file
13
spec/components/admin/stats/chart_component_spec.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe Admin::Stats::ChartComponent do
|
||||
it "renders a tag with JSON data" do
|
||||
create(:user, :level_three, verified_at: "2009-09-09")
|
||||
chart = Ahoy::Chart.new(:level_3_user)
|
||||
|
||||
render_inline Admin::Stats::ChartComponent.new(chart)
|
||||
|
||||
expect(page).to have_css "h2", exact_text: "Level 3 users verified (1)"
|
||||
expect(page).to have_css "[data-graph='{\"x\":[\"2009-09-09\"],\"Level 3 users verified\":[1]}']"
|
||||
end
|
||||
end
|
||||
16
spec/components/admin/stats/event_links_component_spec.rb
Normal file
16
spec/components/admin/stats/event_links_component_spec.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe Admin::Stats::EventLinksComponent do
|
||||
it "renders a list of links" do
|
||||
render_inline Admin::Stats::EventLinksComponent.new(
|
||||
%w[legislation_annotation_created legislation_answer_created]
|
||||
)
|
||||
|
||||
expect(page).to have_link count: 2
|
||||
|
||||
page.find("ul") do |list|
|
||||
expect(list).to have_link "Legislation annotations created"
|
||||
expect(list).to have_link "Legislation answers created"
|
||||
end
|
||||
end
|
||||
end
|
||||
18
spec/components/admin/stats/global_chart_component_spec.rb
Normal file
18
spec/components/admin/stats/global_chart_component_spec.rb
Normal file
@@ -0,0 +1,18 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe Admin::Stats::GlobalChartComponent do
|
||||
before do
|
||||
allow(Ahoy::Chart).to receive(:active_event_names).and_return(
|
||||
%i[budget_investment_created level_3_user]
|
||||
)
|
||||
end
|
||||
|
||||
it "renders an <h2> tag with a graph and links" do
|
||||
render_inline Admin::Stats::GlobalChartComponent.new
|
||||
|
||||
expect(page).to have_css "h2", exact_text: "Graphs"
|
||||
expect(page).to have_css "[data-graph]"
|
||||
expect(page).to have_link "Budget investments created"
|
||||
expect(page).to have_link "Level 3 users verified"
|
||||
end
|
||||
end
|
||||
11
spec/components/admin/stats/sdg_component_spec.rb
Normal file
11
spec/components/admin/stats/sdg_component_spec.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe Admin::Stats::SDGComponent do
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
it "renders a links to go back to the admin stats index" do
|
||||
render_inline Admin::Stats::SDGComponent.new(SDG::Goal.all)
|
||||
|
||||
expect(page).to have_link "Go back", href: admin_stats_path
|
||||
end
|
||||
end
|
||||
@@ -1,68 +0,0 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe Admin::Api::StatsController, :admin do
|
||||
describe "GET index" do
|
||||
context "events or visits not present" do
|
||||
it "responds with bad_request" do
|
||||
get :show
|
||||
|
||||
expect(response).not_to be_ok
|
||||
expect(response).to have_http_status 400
|
||||
end
|
||||
end
|
||||
|
||||
context "events present" do
|
||||
before do
|
||||
time_1 = Time.zone.local(2015, 01, 01)
|
||||
time_2 = Time.zone.local(2015, 01, 02)
|
||||
time_3 = Time.zone.local(2015, 01, 03)
|
||||
|
||||
create(:ahoy_event, name: "foo", time: time_1)
|
||||
create(:ahoy_event, name: "foo", time: time_1)
|
||||
create(:ahoy_event, name: "foo", time: time_2)
|
||||
create(:ahoy_event, name: "bar", time: time_1)
|
||||
create(:ahoy_event, name: "bar", time: time_3)
|
||||
create(:ahoy_event, name: "bar", time: time_3)
|
||||
end
|
||||
|
||||
it "returns single events formated for working with c3.js" do
|
||||
get :show, params: { event: "foo" }
|
||||
|
||||
expect(response).to be_ok
|
||||
expect(response.parsed_body).to eq "x" => ["2015-01-01", "2015-01-02"], "Foo" => [2, 1]
|
||||
end
|
||||
end
|
||||
|
||||
context "visits present" do
|
||||
it "returns visits formated for working with c3.js" do
|
||||
time_1 = Time.zone.local(2015, 01, 01)
|
||||
time_2 = Time.zone.local(2015, 01, 02)
|
||||
|
||||
create(:visit, started_at: time_1)
|
||||
create(:visit, started_at: time_1)
|
||||
create(:visit, started_at: time_2)
|
||||
|
||||
get :show, params: { visits: true }
|
||||
|
||||
expect(response).to be_ok
|
||||
expect(response.parsed_body).to eq "x" => ["2015-01-01", "2015-01-02"], "Visits" => [2, 1]
|
||||
end
|
||||
end
|
||||
|
||||
context "budget investments present" do
|
||||
it "returns budget investments formated for working with c3.js" do
|
||||
time_1 = Time.zone.local(2017, 04, 01)
|
||||
time_2 = Time.zone.local(2017, 04, 02)
|
||||
|
||||
create(:budget_investment, created_at: time_1)
|
||||
create(:budget_investment, created_at: time_2)
|
||||
create(:budget_investment, created_at: time_2)
|
||||
|
||||
get :show, params: { budget_investments: true }
|
||||
|
||||
expect(response).to be_ok
|
||||
expect(response.parsed_body).to eq "x" => ["2017-04-01", "2017-04-02"], "Budget Investments" => [1, 2]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -9,34 +9,6 @@ describe DebatesController do
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST create" do
|
||||
before do
|
||||
InvisibleCaptcha.timestamp_enabled = false
|
||||
end
|
||||
|
||||
after do
|
||||
InvisibleCaptcha.timestamp_enabled = true
|
||||
end
|
||||
|
||||
it "creates an ahoy event" do
|
||||
debate_attributes = {
|
||||
terms_of_service: "1",
|
||||
translations_attributes: {
|
||||
"0" => {
|
||||
title: "A sample debate",
|
||||
description: "this is a sample debate",
|
||||
locale: "en"
|
||||
}
|
||||
}
|
||||
}
|
||||
sign_in create(:user)
|
||||
|
||||
post :create, params: { debate: debate_attributes }
|
||||
expect(Ahoy::Event.where(name: :debate_created).count).to eq 1
|
||||
expect(Ahoy::Event.last.properties["debate_id"]).to eq Debate.last.id
|
||||
end
|
||||
end
|
||||
|
||||
describe "PUT mark_featured" do
|
||||
it "ignores query parameters" do
|
||||
debate = create(:debate)
|
||||
|
||||
@@ -36,27 +36,6 @@ describe Legislation::AnnotationsController do
|
||||
end
|
||||
let(:user) { create(:user, :level_two) }
|
||||
|
||||
it "creates an ahoy event" do
|
||||
sign_in user
|
||||
|
||||
post :create, params: {
|
||||
process_id: legal_process.id,
|
||||
draft_version_id: draft_version.id,
|
||||
legislation_annotation: {
|
||||
"quote" => "ipsum",
|
||||
"ranges" => [{
|
||||
"start" => "/p[1]",
|
||||
"startOffset" => 6,
|
||||
"end" => "/p[1]",
|
||||
"endOffset" => 11
|
||||
}],
|
||||
"text" => "una anotacion"
|
||||
}
|
||||
}
|
||||
expect(Ahoy::Event.where(name: :legislation_annotation_created).count).to eq 1
|
||||
expect(Ahoy::Event.last.properties["legislation_annotation_id"]).to eq Legislation::Annotation.last.id
|
||||
end
|
||||
|
||||
it "does not create an annotation if the draft version is a final version" do
|
||||
sign_in user
|
||||
|
||||
|
||||
@@ -10,20 +10,6 @@ describe Legislation::AnswersController do
|
||||
let(:question_option) { create(:legislation_question_option, question: question, value: "Yes") }
|
||||
let(:user) { create(:user, :level_two) }
|
||||
|
||||
it "creates an ahoy event" do
|
||||
sign_in user
|
||||
|
||||
post :create, params: {
|
||||
process_id: legal_process.id,
|
||||
question_id: question.id,
|
||||
legislation_answer: {
|
||||
legislation_question_option_id: question_option.id
|
||||
}
|
||||
}
|
||||
expect(Ahoy::Event.where(name: :legislation_answer_created).count).to eq 1
|
||||
expect(Ahoy::Event.last.properties["legislation_answer_id"]).to eq Legislation::Answer.last.id
|
||||
end
|
||||
|
||||
it "creates an answer if the process debate phase is open" do
|
||||
sign_in user
|
||||
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
FactoryBot.define do
|
||||
factory :ahoy_event, class: "Ahoy::Event" do
|
||||
id { SecureRandom.uuid }
|
||||
time { DateTime.current }
|
||||
sequence(:name) { |n| "Event #{n} type" }
|
||||
end
|
||||
|
||||
factory :visit do
|
||||
id { SecureRandom.uuid }
|
||||
started_at { DateTime.current }
|
||||
end
|
||||
|
||||
factory :campaign do
|
||||
sequence(:name) { |n| "Campaign #{n}" }
|
||||
sequence(:track_id, &:to_s)
|
||||
end
|
||||
end
|
||||
|
||||
106
spec/models/ahoy/chart_spec.rb
Normal file
106
spec/models/ahoy/chart_spec.rb
Normal file
@@ -0,0 +1,106 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe Ahoy::Chart do
|
||||
describe ".active_events_data_points" do
|
||||
it "groups several events together" do
|
||||
create(:budget_investment, created_at: "2010-01-01")
|
||||
create(:budget_investment, created_at: "2010-01-02")
|
||||
create(:legislation_annotation, created_at: "2010-01-01")
|
||||
create(:legislation_annotation, created_at: "2010-01-03")
|
||||
|
||||
expect(Ahoy::Chart.active_events_data_points).to eq({
|
||||
x: ["2010-01-01", "2010-01-02", "2010-01-03"],
|
||||
"Budget investments created" => [1, 1, 0],
|
||||
"Legislation annotations created" => [1, 0, 1]
|
||||
})
|
||||
end
|
||||
|
||||
it "sorts events alphabetically" do
|
||||
create(:budget_investment, created_at: "2010-01-01")
|
||||
create(:legislation_annotation, created_at: "2010-01-01")
|
||||
|
||||
I18n.with_locale(:es) do
|
||||
expect(Ahoy::Chart.active_events_data_points.keys).to eq([
|
||||
:x,
|
||||
"Anotaciones creadas",
|
||||
"Proyectos de gasto creados"
|
||||
])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#data_points" do
|
||||
it "raises an exception for unknown events" do
|
||||
chart = Ahoy::Chart.new(:mystery)
|
||||
|
||||
expect { chart.data_points }.to raise_exception "Unknown event mystery"
|
||||
end
|
||||
|
||||
it "returns data associated with the event" do
|
||||
time_1 = Time.zone.local(2015, 01, 01)
|
||||
time_2 = Time.zone.local(2015, 01, 02)
|
||||
time_3 = Time.zone.local(2015, 01, 03)
|
||||
|
||||
create(:proposal, created_at: time_1)
|
||||
create(:proposal, created_at: time_1)
|
||||
create(:proposal, created_at: time_2)
|
||||
create(:debate, created_at: time_1)
|
||||
create(:debate, created_at: time_3)
|
||||
|
||||
chart = Ahoy::Chart.new(:proposal_created)
|
||||
|
||||
expect(chart.data_points).to eq x: ["2015-01-01", "2015-01-02"],
|
||||
"Citizen proposals created" => [2, 1]
|
||||
end
|
||||
|
||||
it "accepts strings as the event name" do
|
||||
create(:proposal, created_at: Time.zone.local(2015, 01, 01))
|
||||
create(:debate, created_at: Time.zone.local(2015, 01, 02))
|
||||
|
||||
chart = Ahoy::Chart.new("proposal_created")
|
||||
|
||||
expect(chart.data_points).to eq x: ["2015-01-01"], "Citizen proposals created" => [1]
|
||||
end
|
||||
|
||||
it "returns visits data for the visits event" do
|
||||
time_1 = Time.zone.local(2015, 01, 01)
|
||||
time_2 = Time.zone.local(2015, 01, 02)
|
||||
|
||||
create(:visit, started_at: time_1)
|
||||
create(:visit, started_at: time_1)
|
||||
create(:visit, started_at: time_2)
|
||||
|
||||
chart = Ahoy::Chart.new(:visits)
|
||||
|
||||
expect(chart.data_points).to eq x: ["2015-01-01", "2015-01-02"], "Visits" => [2, 1]
|
||||
end
|
||||
|
||||
it "returns user supports for the budget_investment_supported event" do
|
||||
time_1 = Time.zone.local(2017, 04, 01)
|
||||
time_2 = Time.zone.local(2017, 04, 02)
|
||||
|
||||
create(:vote, votable: create(:budget_investment), created_at: time_1)
|
||||
create(:vote, votable: create(:budget_investment), created_at: time_2)
|
||||
create(:vote, votable: create(:budget_investment), created_at: time_2)
|
||||
create(:vote, votable: create(:proposal), created_at: time_2)
|
||||
|
||||
chart = Ahoy::Chart.new(:budget_investment_supported)
|
||||
|
||||
expect(chart.data_points).to eq x: ["2017-04-01", "2017-04-02"],
|
||||
"Budget investments supported" => [1, 2]
|
||||
end
|
||||
|
||||
it "returns level three verified dates for the level_3_user event" do
|
||||
time_1 = Time.zone.local(2001, 01, 01)
|
||||
time_2 = Time.zone.local(2001, 01, 02)
|
||||
|
||||
create(:user, :level_two, level_two_verified_at: time_1)
|
||||
create(:user, :level_three, verified_at: time_2)
|
||||
create(:user, :level_three, verified_at: time_2, level_two_verified_at: time_1)
|
||||
|
||||
chart = Ahoy::Chart.new(:level_3_user)
|
||||
|
||||
expect(chart.data_points).to eq x: ["2001-01-02"], "Level 3 users verified" => [2]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,18 +2,9 @@ require "rails_helper"
|
||||
|
||||
describe Ahoy::DataSource do
|
||||
describe "#build" do
|
||||
before do
|
||||
time_1 = Time.zone.local(2015, 01, 01)
|
||||
time_2 = Time.zone.local(2015, 01, 02)
|
||||
time_3 = Time.zone.local(2015, 01, 03)
|
||||
|
||||
create(:ahoy_event, name: "foo", time: time_1)
|
||||
create(:ahoy_event, name: "foo", time: time_1)
|
||||
create(:ahoy_event, name: "foo", time: time_2)
|
||||
create(:ahoy_event, name: "bar", time: time_1)
|
||||
create(:ahoy_event, name: "bar", time: time_3)
|
||||
create(:ahoy_event, name: "bar", time: time_3)
|
||||
end
|
||||
let(:january_first) { Time.zone.local(2015, 01, 01) }
|
||||
let(:january_second) { Time.zone.local(2015, 01, 02) }
|
||||
let(:january_third) { Time.zone.local(2015, 01, 03) }
|
||||
|
||||
it "works without data sources" do
|
||||
ds = Ahoy::DataSource.new
|
||||
@@ -22,17 +13,27 @@ describe Ahoy::DataSource do
|
||||
|
||||
it "works with single data sources" do
|
||||
ds = Ahoy::DataSource.new
|
||||
ds.add "foo", Ahoy::Event.where(name: "foo").group_by_day(:time).count
|
||||
ds.add "foo", { january_first => 2, january_second => 1 }
|
||||
expect(ds.build).to eq :x => ["2015-01-01", "2015-01-02"], "foo" => [2, 1]
|
||||
end
|
||||
|
||||
it "combines data sources" do
|
||||
ds = Ahoy::DataSource.new
|
||||
ds.add "foo", Ahoy::Event.where(name: "foo").group_by_day(:time).count
|
||||
ds.add "bar", Ahoy::Event.where(name: "bar").group_by_day(:time).count
|
||||
ds.add "foo", { january_first => 2, january_second => 1 }
|
||||
ds.add "bar", { january_first => 1, january_third => 2 }
|
||||
expect(ds.build).to eq :x => ["2015-01-01", "2015-01-02", "2015-01-03"],
|
||||
"foo" => [2, 1, 0],
|
||||
"bar" => [1, 0, 2]
|
||||
end
|
||||
|
||||
it "returns data ordered by dates" do
|
||||
ds = Ahoy::DataSource.new
|
||||
ds.add "foo", { january_third => 2, january_second => 1 }
|
||||
ds.add "bar", { january_first => 2, january_second => 1 }
|
||||
|
||||
expect(ds.build).to eq :x => ["2015-01-01", "2015-01-02", "2015-01-03"],
|
||||
"foo" => [0, 1, 2],
|
||||
"bar" => [2, 1, 0]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -72,18 +72,6 @@ describe "Stats", :admin do
|
||||
expect(page).to have_content "UNVERIFIED USERS\n1"
|
||||
expect(page).to have_content "TOTAL USERS\n1"
|
||||
end
|
||||
|
||||
scenario "Level 2 user Graph" do
|
||||
create(:geozone)
|
||||
visit account_path
|
||||
click_link "Verify my account"
|
||||
verify_residence
|
||||
confirm_phone
|
||||
|
||||
visit admin_stats_path
|
||||
|
||||
expect(page).to have_content "LEVEL TWO USERS\n1"
|
||||
end
|
||||
end
|
||||
|
||||
describe "Budget investments" do
|
||||
@@ -150,21 +138,30 @@ describe "Stats", :admin do
|
||||
end
|
||||
end
|
||||
|
||||
context "graphs" do
|
||||
scenario "event graphs", :with_frozen_time do
|
||||
campaign = create(:campaign)
|
||||
|
||||
visit root_path(track_id: campaign.track_id)
|
||||
|
||||
expect(page).to have_content "Sign out"
|
||||
describe "graphs", :with_frozen_time do
|
||||
scenario "event graphs" do
|
||||
create(:debate)
|
||||
|
||||
visit admin_stats_path
|
||||
|
||||
within("#stats") do
|
||||
click_link campaign.name
|
||||
click_link "Debates created"
|
||||
end
|
||||
|
||||
expect(page).to have_content "#{campaign.name} (1)"
|
||||
expect(page).to have_content "Debates created (1)"
|
||||
|
||||
within("#graph") do
|
||||
expect(page).to have_content Date.current.strftime("%Y-%m-%d")
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Level 3 user Graph" do
|
||||
create(:user, :level_three)
|
||||
|
||||
visit admin_stats_path
|
||||
click_link "Level 3 users verified"
|
||||
|
||||
expect(page).to have_content "Level 3 users verified (1)"
|
||||
|
||||
within("#graph") do
|
||||
expect(page).to have_content Date.current.strftime("%Y-%m-%d")
|
||||
@@ -183,6 +180,8 @@ describe "Stats", :admin do
|
||||
visit admin_stats_path
|
||||
click_link "Proposal notifications"
|
||||
|
||||
expect(page).to have_link "Go back", href: admin_stats_path
|
||||
|
||||
within("#proposal_notifications_count") do
|
||||
expect(page).to have_content "3"
|
||||
end
|
||||
@@ -232,6 +231,8 @@ describe "Stats", :admin do
|
||||
visit admin_stats_path
|
||||
click_link "Direct messages"
|
||||
|
||||
expect(page).to have_link "Go back", href: admin_stats_path
|
||||
|
||||
within("#direct_messages_count") do
|
||||
expect(page).to have_content "3"
|
||||
end
|
||||
@@ -253,6 +254,8 @@ describe "Stats", :admin do
|
||||
click_link "Polls"
|
||||
end
|
||||
|
||||
expect(page).to have_link "Go back", href: admin_stats_path
|
||||
|
||||
within("#web_participants") do
|
||||
expect(page).to have_content "3"
|
||||
end
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe "Email campaigns", :admin do
|
||||
let!(:campaign1) { create(:campaign) }
|
||||
let!(:campaign2) { create(:campaign) }
|
||||
|
||||
scenario "Track email templates" do
|
||||
3.times { visit root_path(track_id: campaign1.track_id) }
|
||||
5.times { visit root_path(track_id: campaign2.track_id) }
|
||||
|
||||
visit admin_stats_path
|
||||
click_link campaign1.name
|
||||
|
||||
expect(page).to have_content "#{campaign1.name} (3)"
|
||||
|
||||
click_link "Go back"
|
||||
click_link campaign2.name
|
||||
|
||||
expect(page).to have_content "#{campaign2.name} (5)"
|
||||
end
|
||||
|
||||
scenario "Do not track erroneous track_ids" do
|
||||
invalid_id = Campaign.last.id + 1
|
||||
|
||||
visit root_path(track_id: campaign1.track_id)
|
||||
visit root_path(track_id: invalid_id)
|
||||
|
||||
visit admin_stats_path
|
||||
|
||||
expect(page).to have_content campaign1.name
|
||||
expect(page).not_to have_content campaign2.name
|
||||
|
||||
click_link campaign1.name
|
||||
|
||||
expect(page).to have_content "#{campaign1.name} (1)"
|
||||
end
|
||||
end
|
||||
@@ -164,23 +164,25 @@ describe "Notifications" do
|
||||
end
|
||||
|
||||
scenario "With internal link" do
|
||||
admin_notification.update!(link: "/stats")
|
||||
admin_notification.update!(link: "/debates")
|
||||
|
||||
visit notifications_path
|
||||
expect(page).to have_content("Notification title")
|
||||
expect(page).to have_content("Notification body")
|
||||
|
||||
first("#notification_#{notification.id} a").click
|
||||
expect(page).to have_current_path("/stats")
|
||||
|
||||
expect(page).to have_current_path "/debates"
|
||||
end
|
||||
|
||||
scenario "Without a link" do
|
||||
admin_notification.update!(link: "/stats")
|
||||
admin_notification.update!(link: nil)
|
||||
|
||||
visit notifications_path
|
||||
expect(page).to have_content("Notification title")
|
||||
expect(page).to have_content("Notification body")
|
||||
expect(page).not_to have_link(notification_path(notification), visible: :all)
|
||||
|
||||
expect(page).to have_content "Notification title"
|
||||
expect(page).to have_content "Notification body"
|
||||
expect(page).not_to have_link href: notification_path(notification), visible: :all
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe "Stats" do
|
||||
context "Summary" do
|
||||
scenario "General" do
|
||||
create(:debate)
|
||||
2.times { create(:proposal) }
|
||||
3.times { create(:comment, commentable: Debate.first) }
|
||||
4.times { create(:visit) }
|
||||
|
||||
visit stats_path
|
||||
|
||||
expect(page).to have_content "DEBATES\n1"
|
||||
expect(page).to have_content "PROPOSALS\n2"
|
||||
expect(page).to have_content "COMMENTS\n3"
|
||||
expect(page).to have_content "VISITS\n4"
|
||||
end
|
||||
|
||||
scenario "Votes" do
|
||||
create(:debate, voters: Array.new(1) { create(:user) })
|
||||
create(:proposal, voters: Array.new(2) { create(:user) })
|
||||
create(:comment, voters: Array.new(3) { create(:user) })
|
||||
|
||||
visit stats_path
|
||||
|
||||
expect(page).to have_content "VOTES ON DEBATES\n1"
|
||||
expect(page).to have_content "VOTES ON PROPOSALS\n2"
|
||||
expect(page).to have_content "VOTES ON COMMENTS\n3"
|
||||
expect(page).to have_content "TOTAL VOTES\n6"
|
||||
end
|
||||
|
||||
scenario "Users" do
|
||||
1.times { create(:user, :level_three) }
|
||||
2.times { create(:user, :level_two) }
|
||||
2.times { create(:user) }
|
||||
|
||||
visit stats_path
|
||||
|
||||
expect(page).to have_content "VERIFIED USERS\n3"
|
||||
expect(page).to have_content "UNVERIFIED USERS\n2"
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user