Fixes #voodoorai2000 comments
Fixes some comments from #voodoorai2000 for the PR to consul
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var ProposalGraph = function(url) {
|
let ProposalGraph = function(url) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.successfulProposalDataUrl = null;
|
this.successfulProposalDataUrl = null;
|
||||||
this.proposalAchievementsUrl = null;
|
this.proposalAchievementsUrl = null;
|
||||||
@@ -15,12 +15,11 @@
|
|||||||
this.progressLabel = 'Progress';
|
this.progressLabel = 'Progress';
|
||||||
this.supportsLabel = 'Supports';
|
this.supportsLabel = 'Supports';
|
||||||
this.successLabel = 'Success';
|
this.successLabel = 'Success';
|
||||||
this.chart = null;
|
|
||||||
this.goals = null;
|
this.goals = null;
|
||||||
this.achievements = null;
|
this.achievements = null;
|
||||||
this.xColumnValues = null;
|
this.xColumnValues = null;
|
||||||
this.succesfulColumnValues = null;
|
|
||||||
this.progressColumnValues = null;
|
this.progressColumnValues = null;
|
||||||
|
this.resourcesUrl = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
ProposalGraph.prototype.refresh = function() {
|
ProposalGraph.prototype.refresh = function() {
|
||||||
@@ -33,7 +32,7 @@
|
|||||||
|
|
||||||
ProposalGraph.prototype.refreshGoals = function () {
|
ProposalGraph.prototype.refreshGoals = function () {
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
url: '/dashboard/resources.json',
|
url: this.resourcesUrl,
|
||||||
cache: false,
|
cache: false,
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
this.parseGoals(data);
|
this.parseGoals(data);
|
||||||
@@ -42,7 +41,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
ProposalGraph.prototype.parseGoals = function(data) {
|
ProposalGraph.prototype.parseGoals = function(data) {
|
||||||
var i, l;
|
let i, l;
|
||||||
|
|
||||||
this.goals = [];
|
this.goals = [];
|
||||||
for (i = 0, l = data.length; i < l; i += 1) {
|
for (i = 0, l = data.length; i < l; i += 1) {
|
||||||
@@ -67,7 +66,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
ProposalGraph.prototype.parseData = function(data) {
|
ProposalGraph.prototype.parseData = function(data) {
|
||||||
var key;
|
let key;
|
||||||
|
|
||||||
this.xColumnValues = [ ];
|
this.xColumnValues = [ ];
|
||||||
this.progressColumnValues = [ this.progressLabel ];
|
this.progressColumnValues = [ this.progressLabel ];
|
||||||
@@ -94,7 +93,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
ProposalGraph.prototype.parseSuccessfulProposalData = function(data) {
|
ProposalGraph.prototype.parseSuccessfulProposalData = function(data) {
|
||||||
var key;
|
let key;
|
||||||
|
|
||||||
this.successfulColumnValues = [ this.successLabel ];
|
this.successfulColumnValues = [ this.successLabel ];
|
||||||
|
|
||||||
@@ -120,7 +119,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
ProposalGraph.prototype.parseAchievements = function(data) {
|
ProposalGraph.prototype.parseAchievements = function(data) {
|
||||||
var group;
|
let group;
|
||||||
|
|
||||||
this.achievements = [];
|
this.achievements = [];
|
||||||
for (group in data) {
|
for (group in data) {
|
||||||
@@ -128,7 +127,7 @@
|
|||||||
this.addXColumnValue(group);
|
this.addXColumnValue(group);
|
||||||
this.achievements.push({
|
this.achievements.push({
|
||||||
value: group,
|
value: group,
|
||||||
text: data[group][data[group].length - 1].title
|
text: data[group].title
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,12 +137,12 @@
|
|||||||
if (this.xColumnValues.indexOf(value) === -1) {
|
if (this.xColumnValues.indexOf(value) === -1) {
|
||||||
this.xColumnValues.push(value);
|
this.xColumnValues.push(value);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
ProposalGraph.prototype.draw = function(data) {
|
ProposalGraph.prototype.draw = function() {
|
||||||
this.formatXColumnValues();
|
this.formatXColumnValues();
|
||||||
|
|
||||||
this.chart = c3.generate({
|
c3.generate({
|
||||||
bindto: '#' + this.targetId,
|
bindto: '#' + this.targetId,
|
||||||
data: {
|
data: {
|
||||||
x: 'x',
|
x: 'x',
|
||||||
@@ -176,9 +175,6 @@
|
|||||||
y: {
|
y: {
|
||||||
lines: this.goals
|
lines: this.goals
|
||||||
}
|
}
|
||||||
//x: {
|
|
||||||
// lines: this.achievements
|
|
||||||
//}
|
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
position: 'right'
|
position: 'right'
|
||||||
@@ -187,7 +183,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
ProposalGraph.prototype.formatXColumnValues = function () {
|
ProposalGraph.prototype.formatXColumnValues = function () {
|
||||||
var i, l, parts;
|
let i, l, parts;
|
||||||
|
|
||||||
this.xColumnValues = this.xColumnValues.sort();
|
this.xColumnValues = this.xColumnValues.sort();
|
||||||
|
|
||||||
@@ -199,7 +195,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.xColumnValues.unshift('x');
|
this.xColumnValues.unshift('x');
|
||||||
}
|
};
|
||||||
|
|
||||||
ProposalGraph.prototype.isDailyGrouped = function() {
|
ProposalGraph.prototype.isDailyGrouped = function() {
|
||||||
return this.groupBy === undefined || this.groupBy === '' || this.groupBy === null
|
return this.groupBy === undefined || this.groupBy === '' || this.groupBy === null
|
||||||
@@ -207,7 +203,7 @@
|
|||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('[data-proposal-graph-url]').each(function () {
|
$('[data-proposal-graph-url]').each(function () {
|
||||||
var graph = new ProposalGraph($(this).data('proposal-graph-url'));
|
let graph = new ProposalGraph($(this).data('proposal-graph-url'));
|
||||||
graph.successfulProposalDataUrl = $(this).data('successful-proposal-graph-url');
|
graph.successfulProposalDataUrl = $(this).data('successful-proposal-graph-url');
|
||||||
graph.proposalAchievementsUrl = $(this).data('proposal-achievements-url');
|
graph.proposalAchievementsUrl = $(this).data('proposal-achievements-url');
|
||||||
graph.targetId = $(this).attr('id');
|
graph.targetId = $(this).attr('id');
|
||||||
@@ -216,6 +212,7 @@
|
|||||||
graph.supportsLabel = $(this).data('proposal-graph-supports-label');
|
graph.supportsLabel = $(this).data('proposal-graph-supports-label');
|
||||||
graph.successLabel = $(this).data('proposal-graph-success-label');
|
graph.successLabel = $(this).data('proposal-graph-success-label');
|
||||||
graph.proposalSuccess = parseInt($(this).data('proposal-success'), 10);
|
graph.proposalSuccess = parseInt($(this).data('proposal-success'), 10);
|
||||||
|
graph.resourcesUrl = $(this).data('proposal-resources-url');
|
||||||
|
|
||||||
graph.refresh();
|
graph.refresh();
|
||||||
});
|
});
|
||||||
|
|||||||
15
app/controllers/concerns/dashboard/expects_date_range.rb
Normal file
15
app/controllers/concerns/dashboard/expects_date_range.rb
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
module Dashboard::ExpectsDateRange
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
include Dashboard::HasProposal
|
||||||
|
|
||||||
|
def start_date
|
||||||
|
return Date.parse(params[:start_date]) unless params[:start_date].blank?
|
||||||
|
proposal.created_at.to_date
|
||||||
|
end
|
||||||
|
|
||||||
|
def end_date
|
||||||
|
return Date.parse(params[:end_date]) unless params[:end_date].blank?
|
||||||
|
Date.today
|
||||||
|
end
|
||||||
|
end
|
||||||
7
app/controllers/concerns/dashboard/has_proposal.rb
Normal file
7
app/controllers/concerns/dashboard/has_proposal.rb
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
module Dashboard::HasProposal
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
def proposal
|
||||||
|
@proposal ||= Proposal.includes(:community).find(params[:proposal_id])
|
||||||
|
end
|
||||||
|
end
|
||||||
44
app/controllers/dashboard/achievements_controller.rb
Normal file
44
app/controllers/dashboard/achievements_controller.rb
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
class Dashboard::AchievementsController < Dashboard::BaseController
|
||||||
|
include Dashboard::ExpectsDateRange
|
||||||
|
|
||||||
|
def index
|
||||||
|
authorize! :dashboard, proposal
|
||||||
|
render json: processed_groups
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def processed_groups
|
||||||
|
grouped_results = groups
|
||||||
|
grouped_results.each do |key, results|
|
||||||
|
grouped_results[key] = {
|
||||||
|
executed_at: results.last.executed_at,
|
||||||
|
title: results.last.action.title
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
grouped_results
|
||||||
|
end
|
||||||
|
|
||||||
|
def groups
|
||||||
|
if params[:group_by] == 'week'
|
||||||
|
return executed_proposed_actions.group_by { |v| "#{v.executed_at.to_date.cweek}/#{v.executed_at.to_date.year}"}
|
||||||
|
end
|
||||||
|
|
||||||
|
if params[:group_by] == 'month'
|
||||||
|
return executed_proposed_actions.group_by { |v| "#{v.executed_at.to_date.year}-#{v.executed_at.to_date.month}"}
|
||||||
|
end
|
||||||
|
|
||||||
|
executed_proposed_actions.group_by { |a| a.executed_at.to_date }
|
||||||
|
end
|
||||||
|
|
||||||
|
def executed_proposed_actions
|
||||||
|
@executed_proposed_actions ||= Dashboard::ExecutedAction
|
||||||
|
.joins(:action)
|
||||||
|
.includes(:action)
|
||||||
|
.where(proposal: proposal)
|
||||||
|
.where(executed_at: start_date.beginning_of_day..end_date.end_of_day)
|
||||||
|
.where(dashboard_actions: { action_type: 0 })
|
||||||
|
.order(executed_at: :asc)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
class Dashboard::BaseController < ApplicationController
|
class Dashboard::BaseController < ApplicationController
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
|
|
||||||
|
include Dashboard::HasProposal
|
||||||
|
|
||||||
helper_method :proposal, :proposed_actions, :resource, :resources, :next_goal, :next_goal_supports, :next_goal_progress, :community_members_count
|
helper_method :proposal, :proposed_actions, :resource, :resources, :next_goal, :next_goal_supports, :next_goal_progress, :community_members_count
|
||||||
|
|
||||||
respond_to :html
|
respond_to :html
|
||||||
@@ -8,10 +10,6 @@ class Dashboard::BaseController < ApplicationController
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def proposal
|
|
||||||
@proposal ||= Proposal.includes(:community).find(params[:proposal_id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def proposed_actions
|
def proposed_actions
|
||||||
@proposed_actions ||= Dashboard::Action.proposed_actions.active_for(proposal).order(order: :asc)
|
@proposed_actions ||= Dashboard::Action.proposed_actions.active_for(proposal).order(order: :asc)
|
||||||
end
|
end
|
||||||
|
|||||||
58
app/controllers/dashboard/successful_supports_controller.rb
Normal file
58
app/controllers/dashboard/successful_supports_controller.rb
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
class Dashboard::SuccessfulSupportsController < Dashboard::BaseController
|
||||||
|
include Dashboard::ExpectsDateRange
|
||||||
|
|
||||||
|
def index
|
||||||
|
authorize! :dashboard, proposal
|
||||||
|
render json: accumulated_grouped_supports
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def accumulated_grouped_supports
|
||||||
|
grouped_votes = grouped_supports
|
||||||
|
grouped_votes.each do |group, votes|
|
||||||
|
grouped_votes[group] = votes.inject(0) { |sum, vote| sum + vote.vote_weight }
|
||||||
|
end
|
||||||
|
|
||||||
|
accumulated = 0
|
||||||
|
grouped_votes.each do |k, v|
|
||||||
|
accumulated += v
|
||||||
|
grouped_votes[k] = accumulated
|
||||||
|
end
|
||||||
|
|
||||||
|
grouped_votes
|
||||||
|
end
|
||||||
|
|
||||||
|
def grouped_supports
|
||||||
|
if params[:group_by] == 'week'
|
||||||
|
return supports.group_by { |v| "#{v.voted_at.to_date.cweek}/#{v.voted_at.to_date.year}" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if params[:group_by] == 'month'
|
||||||
|
return supports.group_by { |v| "#{v.voted_at.to_date.year}-#{v.voted_at.to_date.month}" }
|
||||||
|
end
|
||||||
|
|
||||||
|
supports.group_by { |v| v.voted_at.to_date }
|
||||||
|
end
|
||||||
|
|
||||||
|
def supports
|
||||||
|
return [] if successful_proposal.nil?
|
||||||
|
|
||||||
|
Vote
|
||||||
|
.select("created_at + interval '#{days_diff} day' voted_at, *")
|
||||||
|
.where(votable: successful_proposal)
|
||||||
|
.where("created_at + interval '#{days_diff} day' between ? and ?", start_date.beginning_of_day, end_date.end_of_day)
|
||||||
|
.order(created_at: :asc)
|
||||||
|
end
|
||||||
|
|
||||||
|
def successful_proposal
|
||||||
|
@successful_proposal ||= Proposal.find_by(id: Setting['proposals.successful_proposal_id'])
|
||||||
|
end
|
||||||
|
|
||||||
|
def days_diff
|
||||||
|
return 0 if successful_proposal.nil?
|
||||||
|
return 0 if proposal.published_at.nil?
|
||||||
|
|
||||||
|
(proposal.published_at.to_date - successful_proposal.published_at.to_date).to_i
|
||||||
|
end
|
||||||
|
end
|
||||||
43
app/controllers/dashboard/supports_controller.rb
Normal file
43
app/controllers/dashboard/supports_controller.rb
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
class Dashboard::SupportsController < Dashboard::BaseController
|
||||||
|
include Dashboard::ExpectsDateRange
|
||||||
|
|
||||||
|
def index
|
||||||
|
authorize! :dashboard, proposal
|
||||||
|
render json: accumulated_supports
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def accumulated_supports
|
||||||
|
grouped_votes = grouped_supports
|
||||||
|
grouped_votes.each do |group, votes|
|
||||||
|
grouped_votes[group] = votes.inject(0) { |sum, vote| sum + vote.vote_weight }
|
||||||
|
end
|
||||||
|
|
||||||
|
accumulated = 0
|
||||||
|
grouped_votes.each do |k, v|
|
||||||
|
accumulated += v
|
||||||
|
grouped_votes[k] = accumulated
|
||||||
|
end
|
||||||
|
|
||||||
|
grouped_votes
|
||||||
|
end
|
||||||
|
|
||||||
|
def grouped_supports
|
||||||
|
if params[:group_by] == 'week'
|
||||||
|
return supports.group_by { |v| "#{v.created_at.to_date.cweek}/#{v.created_at.to_date.year}" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if params[:group_by] == 'month'
|
||||||
|
return supports.group_by { |v| "#{v.created_at.to_date.year}-#{v.created_at.to_date.month}" }
|
||||||
|
end
|
||||||
|
|
||||||
|
supports.group_by { |v| v.created_at.to_date }
|
||||||
|
end
|
||||||
|
|
||||||
|
def supports
|
||||||
|
@supports ||= Vote
|
||||||
|
.where(votable: proposal, created_at: start_date.beginning_of_day..end_date.end_of_day)
|
||||||
|
.order(created_at: :asc)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -37,7 +37,7 @@ class DashboardController < Dashboard::BaseController
|
|||||||
if @dashboard_executed_action.save
|
if @dashboard_executed_action.save
|
||||||
Dashboard::AdministratorTask.create(source: @dashboard_executed_action)
|
Dashboard::AdministratorTask.create(source: @dashboard_executed_action)
|
||||||
|
|
||||||
redirect_to progress_proposal_dashboard_index_path(proposal.to_param), { flash: { info: t('.success') } }
|
redirect_to progress_proposal_dashboard_index_path(proposal.to_param), { flash: { info: t('dashboard.create_request.success') } }
|
||||||
else
|
else
|
||||||
flash.now[:alert] = @dashboard_executed_action.errors.full_messages.join('<br>')
|
flash.now[:alert] = @dashboard_executed_action.errors.full_messages.join('<br>')
|
||||||
render :new_request
|
render :new_request
|
||||||
@@ -52,21 +52,6 @@ class DashboardController < Dashboard::BaseController
|
|||||||
authorize! :dashboard, proposal
|
authorize! :dashboard, proposal
|
||||||
end
|
end
|
||||||
|
|
||||||
def supports
|
|
||||||
authorize! :dashboard, proposal
|
|
||||||
render json: ProposalSupportsQuery.for(params)
|
|
||||||
end
|
|
||||||
|
|
||||||
def successful_supports
|
|
||||||
authorize! :dashboard, proposal
|
|
||||||
render json: SuccessfulProposalSupportsQuery.for(params)
|
|
||||||
end
|
|
||||||
|
|
||||||
def achievements
|
|
||||||
authorize! :dashboard, proposal
|
|
||||||
render json: ProposalAchievementsQuery.for(params)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def dashboard_action
|
def dashboard_action
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ class Poll::Question < ActiveRecord::Base
|
|||||||
acts_as_paranoid column: :hidden_at
|
acts_as_paranoid column: :hidden_at
|
||||||
include ActsAsParanoidAliases
|
include ActsAsParanoidAliases
|
||||||
|
|
||||||
belongs_to :poll, inverse_of: :questions
|
belongs_to :poll
|
||||||
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
|
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
|
||||||
|
|
||||||
has_many :comments, as: :commentable
|
has_many :comments, as: :commentable
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
class ProposalAchievementsQuery
|
|
||||||
attr_reader :params
|
|
||||||
|
|
||||||
def self.for(params)
|
|
||||||
query = ProposalAchievementsQuery.new params
|
|
||||||
query.results
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(params)
|
|
||||||
@params = params
|
|
||||||
end
|
|
||||||
|
|
||||||
def results
|
|
||||||
grouped_results = groups
|
|
||||||
grouped_results.each do |key, achievements|
|
|
||||||
grouped_results[key] = []
|
|
||||||
|
|
||||||
achievements.each do |achievement|
|
|
||||||
grouped_results[key] << {
|
|
||||||
executed_at: achievements.last.executed_at,
|
|
||||||
title: achievements.last.action.title
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
grouped_results
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def groups
|
|
||||||
return achievements.group_by { |v| v.executed_at.to_date.year } if params[:group_by] == 'year'
|
|
||||||
return achievements.group_by { |v| "#{v.executed_at.to_date.cweek}/#{v.executed_at.to_date.year}" } if params[:group_by] == 'week'
|
|
||||||
return achievements.group_by { |v| "#{v.executed_at.to_date.year}-#{v.executed_at.to_date.month}" } if params[:group_by] == 'month'
|
|
||||||
achievements.group_by { |a| a.executed_at.to_date }
|
|
||||||
end
|
|
||||||
|
|
||||||
def achievements
|
|
||||||
Dashboard::ExecutedAction
|
|
||||||
.joins(:action)
|
|
||||||
.includes(:action)
|
|
||||||
.where(proposal: proposal, executed_at: start_date.beginning_of_day..end_date.end_of_day)
|
|
||||||
.where(dashboard_actions: { action_type: 0 })
|
|
||||||
.order(executed_at: :asc)
|
|
||||||
end
|
|
||||||
|
|
||||||
def proposal
|
|
||||||
@proposal ||= Proposal.find(params[:proposal_id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def start_date
|
|
||||||
return Date.parse(params[:start_date]) unless params[:start_date].blank?
|
|
||||||
proposal.created_at.to_date
|
|
||||||
end
|
|
||||||
|
|
||||||
def end_date
|
|
||||||
return Date.parse(params[:end_date]) unless params[:end_date].blank?
|
|
||||||
Date.today
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
class ProposalSupportsQuery
|
|
||||||
attr_reader :params
|
|
||||||
|
|
||||||
def self.for(params)
|
|
||||||
query = ProposalSupportsQuery.new params
|
|
||||||
query.results
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(params)
|
|
||||||
@params = params
|
|
||||||
end
|
|
||||||
|
|
||||||
def results
|
|
||||||
grouped_votes = groups
|
|
||||||
grouped_votes.each do |group, votes|
|
|
||||||
grouped_votes[group] = votes.inject(0) { |sum, vote| sum + vote.vote_weight }
|
|
||||||
end
|
|
||||||
|
|
||||||
accumulated = 0
|
|
||||||
grouped_votes.each do |k, v|
|
|
||||||
accumulated += v
|
|
||||||
grouped_votes[k] = accumulated
|
|
||||||
end
|
|
||||||
|
|
||||||
grouped_votes
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def groups
|
|
||||||
return votes.group_by { |v| v.created_at.to_date.year } if params[:group_by] == 'year'
|
|
||||||
return votes.group_by { |v| "#{v.created_at.to_date.cweek}/#{v.created_at.to_date.year}" } if params[:group_by] == 'week'
|
|
||||||
return votes.group_by { |v| "#{v.created_at.to_date.year}-#{v.created_at.to_date.month}" } if params[:group_by] == 'month'
|
|
||||||
votes.group_by { |v| v.created_at.to_date }
|
|
||||||
end
|
|
||||||
|
|
||||||
def votes
|
|
||||||
Vote.where(votable: proposal, created_at: start_date.beginning_of_day..end_date.end_of_day).order(created_at: :asc)
|
|
||||||
end
|
|
||||||
|
|
||||||
def proposal
|
|
||||||
@proposal ||= Proposal.find(params[:proposal_id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def start_date
|
|
||||||
return Date.parse(params[:start_date]) unless params[:start_date].blank?
|
|
||||||
proposal.created_at.to_date
|
|
||||||
end
|
|
||||||
|
|
||||||
def end_date
|
|
||||||
return Date.parse(params[:end_date]) unless params[:end_date].blank?
|
|
||||||
Date.today
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
class SuccessfulProposalSupportsQuery
|
|
||||||
attr_reader :params
|
|
||||||
|
|
||||||
def self.for(params)
|
|
||||||
query = SuccessfulProposalSupportsQuery.new params
|
|
||||||
query.results
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(params)
|
|
||||||
@params = params
|
|
||||||
end
|
|
||||||
|
|
||||||
def results
|
|
||||||
grouped_votes = groups
|
|
||||||
grouped_votes.each do |group, votes|
|
|
||||||
grouped_votes[group] = votes.inject(0) { |sum, vote| sum + vote.vote_weight }
|
|
||||||
end
|
|
||||||
|
|
||||||
accumulated = 0
|
|
||||||
grouped_votes.each do |k, v|
|
|
||||||
accumulated += v
|
|
||||||
grouped_votes[k] = accumulated
|
|
||||||
end
|
|
||||||
|
|
||||||
grouped_votes
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def groups
|
|
||||||
return votes.group_by { |v| v.voted_at.to_date.year } if params[:group_by] == 'year'
|
|
||||||
return votes.group_by { |v| "#{v.voted_at.to_date.cweek}/#{v.voted_at.to_date.year}" } if params[:group_by] == 'week'
|
|
||||||
return votes.group_by { |v| "#{v.voted_at.to_date.year}-#{v.voted_at.to_date.month}" } if params[:group_by] == 'month'
|
|
||||||
votes.group_by { |v| v.voted_at.to_date }
|
|
||||||
end
|
|
||||||
|
|
||||||
def votes
|
|
||||||
return [] if successful_proposal.nil?
|
|
||||||
|
|
||||||
Vote
|
|
||||||
.select("created_at + interval '#{days_diff} day' voted_at, *")
|
|
||||||
.where(votable: successful_proposal)
|
|
||||||
.where("created_at + interval '#{days_diff} day' between ? and ?", start_date.beginning_of_day, end_date.end_of_day)
|
|
||||||
.order(created_at: :asc)
|
|
||||||
end
|
|
||||||
|
|
||||||
def proposal
|
|
||||||
@proposal ||= Proposal.find(params[:proposal_id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def successful_proposal
|
|
||||||
@successful_proposal ||= Proposal.find_by(id: Setting['proposals.successful_proposal_id'])
|
|
||||||
end
|
|
||||||
|
|
||||||
def days_diff
|
|
||||||
return 0 if successful_proposal.nil?
|
|
||||||
return 0 if proposal.published_at.nil?
|
|
||||||
|
|
||||||
(proposal.published_at.to_date - successful_proposal.published_at.to_date).to_i
|
|
||||||
end
|
|
||||||
|
|
||||||
def start_date
|
|
||||||
return Date.parse(params[:start_date]) unless params[:start_date].blank?
|
|
||||||
proposal.created_at.to_date
|
|
||||||
end
|
|
||||||
|
|
||||||
def end_date
|
|
||||||
return Date.parse(params[:end_date]) unless params[:end_date].blank?
|
|
||||||
Date.today
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@@ -251,4 +251,5 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,14 +18,15 @@
|
|||||||
|
|
||||||
<div class="small-12 column">
|
<div class="small-12 column">
|
||||||
<div id="proposal-graph"
|
<div id="proposal-graph"
|
||||||
data-proposal-graph-url="<%= supports_proposal_dashboard_index_path(proposal, format: :json) %>"
|
data-proposal-graph-url="<%= proposal_dashboard_supports_path(proposal, format: :json) %>"
|
||||||
data-successful-proposal-graph-url="<%= successful_supports_proposal_dashboard_index_path(proposal, format: :json) %>"
|
data-successful-proposal-graph-url="<%= proposal_dashboard_successful_supports_path(proposal, format: :json) %>"
|
||||||
data-proposal-achievements-url="<%= achievements_proposal_dashboard_index_path(proposal, format: :json) %>"
|
data-proposal-achievements-url="<%= proposal_dashboard_achievements_path(proposal, format: :json) %>"
|
||||||
data-proposal-graph-group-by="<%= params[:group_by] %>"
|
data-proposal-graph-group-by="<%= params[:group_by] %>"
|
||||||
data-proposal-graph-progress-label="<%= t("dashboard.progress.progress") %>"
|
data-proposal-graph-progress-label="<%= t("dashboard.progress.progress") %>"
|
||||||
data-proposal-graph-supports-label="<%= t("dashboard.progress.supports") %>"
|
data-proposal-graph-supports-label="<%= t("dashboard.progress.supports") %>"
|
||||||
data-proposal-graph-success-label="<%= t("dashboard.progress.success") %>"
|
data-proposal-graph-success-label="<%= t("dashboard.progress.success") %>"
|
||||||
data-proposal-success="<%= Setting["votes_for_proposal_success"] %>"
|
data-proposal-success="<%= Setting["votes_for_proposal_success"] %>"
|
||||||
|
data-proposal-resources-url="<%= proposal_dashboard_resources_path(proposal, format: :json) %>"
|
||||||
class="c3 proposal-graph"
|
class="c3 proposal-graph"
|
||||||
style="max-height: 320px; position: relative;"></div>
|
style="max-height: 320px; position: relative;"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
<div class="row margin-top">
|
<div class="row margin-top">
|
||||||
<div class="small-12 column">
|
<div class="small-12 column">
|
||||||
<ul class="menu simple clear">
|
<ul class="menu simple clear">
|
||||||
<%# if current_user && current_user.administrator? || @poll.results_enabled? %>
|
|
||||||
<% if can?(:results, @poll) %>
|
<% if can?(:results, @poll) %>
|
||||||
<% if controller_name == "polls" && action_name == "results" %>
|
<% if controller_name == "polls" && action_name == "results" %>
|
||||||
<li class="is-active">
|
<li class="is-active">
|
||||||
|
|||||||
@@ -1,16 +1,9 @@
|
|||||||
namespace :dashboard do
|
|
||||||
resources :resources, only: [:index]
|
|
||||||
end
|
|
||||||
|
|
||||||
resources :proposals do
|
resources :proposals do
|
||||||
resources :dashboard, only: [:index] do
|
resources :dashboard, only: [:index] do
|
||||||
collection do
|
collection do
|
||||||
patch :publish
|
patch :publish
|
||||||
get :supports
|
|
||||||
get :successful_supports
|
|
||||||
get :progress
|
get :progress
|
||||||
get :community
|
get :community
|
||||||
get :achievements
|
|
||||||
end
|
end
|
||||||
|
|
||||||
member do
|
member do
|
||||||
@@ -21,6 +14,10 @@ resources :proposals do
|
|||||||
end
|
end
|
||||||
|
|
||||||
namespace :dashboard do
|
namespace :dashboard do
|
||||||
|
resources :resources, only: [:index]
|
||||||
|
resources :achievements, only: [:index]
|
||||||
|
resources :successful_supports, only: [:index]
|
||||||
|
resources :supports, only: [:index]
|
||||||
resources :polls, except: [:show, :destroy]
|
resources :polls, except: [:show, :destroy]
|
||||||
resources :mailing, only: [:index, :new, :create]
|
resources :mailing, only: [:index, :new, :create]
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -69,4 +69,11 @@ section "Creating Settings" do
|
|||||||
Setting['feature.homepage.widgets.feeds.proposals'] = true
|
Setting['feature.homepage.widgets.feeds.proposals'] = true
|
||||||
Setting['feature.homepage.widgets.feeds.debates'] = true
|
Setting['feature.homepage.widgets.feeds.debates'] = true
|
||||||
Setting['feature.homepage.widgets.feeds.processes'] = true
|
Setting['feature.homepage.widgets.feeds.processes'] = true
|
||||||
|
|
||||||
|
Setting['proposals.successful_proposal_id'] = nil
|
||||||
|
Setting['proposals.poll_short_title'] = nil
|
||||||
|
Setting['proposals.poll_description'] = nil
|
||||||
|
Setting['proposals.poll_link'] = nil
|
||||||
|
Setting['proposals.email_short_title'] = nil
|
||||||
|
Setting['proposals.email_description'] = nil
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
class AddPublishedAtToProposal < ActiveRecord::Migration
|
class AddPublishedAtToProposal < ActiveRecord::Migration
|
||||||
def change
|
def change
|
||||||
add_column :proposals, :published_at, :datetime, null: true
|
add_column :proposals, :published_at, :datetime, null: true
|
||||||
|
|
||||||
Proposal.draft.find_each do |proposal|
|
|
||||||
proposal.update(published_at: proposal.created_at)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
class AddTimestampsToDashboardActions < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :dashboard_actions, :created_at, :datetime
|
||||||
|
add_column :dashboard_actions, :updated_at, :datetime
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20180723112930) do
|
ActiveRecord::Schema.define(version: 20180726055120) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
@@ -318,6 +318,8 @@ ActiveRecord::Schema.define(version: 20180723112930) do
|
|||||||
t.datetime "hidden_at"
|
t.datetime "hidden_at"
|
||||||
t.integer "action_type", default: 0, null: false
|
t.integer "action_type", default: 0, null: false
|
||||||
t.string "short_description"
|
t.string "short_description"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "dashboard_administrator_tasks", force: :cascade do |t|
|
create_table "dashboard_administrator_tasks", force: :cascade do |t|
|
||||||
|
|||||||
@@ -27,6 +27,13 @@ namespace :proposal_actions do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc 'Publish all proposals'
|
||||||
|
task publish_all: :environment do
|
||||||
|
Proposal.draft.find_each do |proposal|
|
||||||
|
proposal.update(published_at: proposal.created_at)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
desc 'Simulate successful proposal'
|
desc 'Simulate successful proposal'
|
||||||
task create_successful_proposal: :environment do
|
task create_successful_proposal: :environment do
|
||||||
expected_supports = [
|
expected_supports = [
|
||||||
|
|||||||
@@ -1038,7 +1038,7 @@ LOREM_IPSUM
|
|||||||
end
|
end
|
||||||
|
|
||||||
factory :dashboard_action, class: 'Dashboard::Action' do
|
factory :dashboard_action, class: 'Dashboard::Action' do
|
||||||
title { Faker::Lorem.sentence }
|
title { Faker::Lorem.sentence[0..80] }
|
||||||
description { Faker::Lorem.sentence }
|
description { Faker::Lorem.sentence }
|
||||||
link nil
|
link nil
|
||||||
request_to_administrators true
|
request_to_administrators true
|
||||||
|
|||||||
@@ -26,6 +26,14 @@ feature 'Polls' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario "Proposal polls won't be listed" do
|
||||||
|
proposal = create(:proposal)
|
||||||
|
_poll = create(:poll, related: proposal)
|
||||||
|
|
||||||
|
visit polls_path
|
||||||
|
expect(page).to have_content('There are no open votings')
|
||||||
|
end
|
||||||
|
|
||||||
scenario 'Filtering polls' do
|
scenario 'Filtering polls' do
|
||||||
create(:poll, name: "Current poll")
|
create(:poll, name: "Current poll")
|
||||||
create(:poll, :incoming, name: "Incoming poll")
|
create(:poll, :incoming, name: "Incoming poll")
|
||||||
|
|||||||
@@ -1029,12 +1029,12 @@ describe Budget::Investment do
|
|||||||
investment.heading = heading2
|
investment.heading = heading2
|
||||||
investment.store_reclassified_votes("heading_changed")
|
investment.store_reclassified_votes("heading_changed")
|
||||||
|
|
||||||
|
reclassified_vote = Budget::ReclassifiedVote.first
|
||||||
|
|
||||||
expect(Budget::ReclassifiedVote.count).to eq(3)
|
expect(Budget::ReclassifiedVote.count).to eq(3)
|
||||||
Budget::ReclassifiedVote.find_each do |reclassified_vote|
|
expect(reclassified_vote.investment_id).to eq(investment.id)
|
||||||
expect(reclassified_vote.investment_id).to eq(investment.id)
|
expect(reclassified_vote.user_id).to eq(Budget::Ballot.first.user.id)
|
||||||
expect(reclassified_vote.reason).to eq("heading_changed")
|
expect(reclassified_vote.reason).to eq("heading_changed")
|
||||||
expect(Budget::Ballot.where(user_id: reclassified_vote.user_id)).not_to be_empty
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -18,118 +18,135 @@ describe Dashboard::Action do
|
|||||||
let(:request_to_administrators) { true }
|
let(:request_to_administrators) { true }
|
||||||
let(:action_type) { 'resource' }
|
let(:action_type) { 'resource' }
|
||||||
|
|
||||||
it { should be_valid }
|
it 'is invalid when title is blank' do
|
||||||
|
action = build(:dashboard_action, title: '')
|
||||||
context 'when validating title' do
|
expect(action).not_to be_valid
|
||||||
context 'and title is blank' do
|
|
||||||
let(:title) { nil }
|
|
||||||
|
|
||||||
it { should_not be_valid }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'and title is very short' do
|
|
||||||
let(:title) { 'abc' }
|
|
||||||
|
|
||||||
it { should_not be_valid }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'and title is very long' do
|
|
||||||
let(:title) { 'a' * 81 }
|
|
||||||
|
|
||||||
it { should_not be_valid }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when validating day_offset' do
|
it 'is invalid when title is too short' do
|
||||||
context 'and day_offset is nil' do
|
action = build(:dashboard_action, title: 'abc')
|
||||||
let(:day_offset) { nil }
|
expect(action).not_to be_valid
|
||||||
|
|
||||||
it { should_not be_valid }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'and day_offset is negative' do
|
|
||||||
let(:day_offset) { -1 }
|
|
||||||
|
|
||||||
it { should_not be_valid }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'and day_offset is not an integer' do
|
|
||||||
let(:day_offset) { 1.23 }
|
|
||||||
|
|
||||||
it { should_not be_valid }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when validating required_supports' do
|
it 'is invalid when title is too long' do
|
||||||
context 'and required_supports is nil' do
|
action = build(:dashboard_action, title: 'a' * 81)
|
||||||
let(:required_supports) { nil }
|
expect(action).not_to be_valid
|
||||||
|
|
||||||
it { should_not be_valid }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'and required_supports is negative' do
|
|
||||||
let(:required_supports) { -1 }
|
|
||||||
|
|
||||||
it { should_not be_valid }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'and required_supports is not an integer' do
|
|
||||||
let(:required_supports) { 1.23 }
|
|
||||||
|
|
||||||
it { should_not be_valid }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when action type is nil' do
|
it 'is invalid when day_offset is not defined' do
|
||||||
let(:action_type) { nil }
|
action = build(:dashboard_action, day_offset: nil)
|
||||||
|
expect(action).not_to be_valid
|
||||||
it { should_not be_valid }
|
end
|
||||||
|
|
||||||
|
it 'is invalid when day_offset is negative' do
|
||||||
|
action = build(:dashboard_action, day_offset: -1)
|
||||||
|
expect(action).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is invalid when day_offset not an integer' do
|
||||||
|
action = build(:dashboard_action, day_offset: 1.23)
|
||||||
|
expect(action).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is invalid when required_supports is nil' do
|
||||||
|
action = build(:dashboard_action, required_supports: nil)
|
||||||
|
expect(action).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is invalid when required_supports is negative' do
|
||||||
|
action = build(:dashboard_action, required_supports: -1)
|
||||||
|
expect(action).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is invalid when required_supports is not an integer' do
|
||||||
|
action = build(:dashboard_action, required_supports: 1.23)
|
||||||
|
expect(action).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is invalid when action_type is nil' do
|
||||||
|
action = build(:dashboard_action, action_type: nil)
|
||||||
|
expect(action).not_to be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'active_for?' do
|
context 'active_for?' do
|
||||||
let(:proposal) { create(:proposal, published_at: published_at, cached_votes_up: cached_votes_up) }
|
it 'is active when required supports is 0 and day_offset is 0' do
|
||||||
let(:published_at) { Time.current }
|
action = build(:dashboard_action, required_supports: 0, day_offset: 0)
|
||||||
let(:cached_votes_up) { Proposal.votes_needed_for_success + 100 }
|
proposal = build(:proposal)
|
||||||
|
|
||||||
it { should be_active_for(proposal) }
|
|
||||||
|
|
||||||
context 'and not enough supports' do
|
|
||||||
let(:required_supports) { cached_votes_up + 100 }
|
|
||||||
|
|
||||||
it { should_not be_active_for(proposal) }
|
expect(action).to be_active_for(proposal)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'and not passed enough time since publication' do
|
it 'is active when published after day_offset' do
|
||||||
let(:day_offset) { 10 }
|
action = build(:dashboard_action, required_supports: 0, day_offset: 10)
|
||||||
|
proposal = build(:proposal, published_at: Time.current - 10.days)
|
||||||
|
|
||||||
|
expect(action).to be_active_for(proposal)
|
||||||
|
end
|
||||||
|
|
||||||
it { should_not be_active_for(proposal) }
|
it 'is active when have enough supports' do
|
||||||
|
action = build(:dashboard_action, required_supports: 10, day_offset: 0)
|
||||||
|
proposal = build(:proposal, cached_votes_up: 10)
|
||||||
|
|
||||||
|
expect(action).to be_active_for(proposal)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is not active when not enough time published' do
|
||||||
|
action = build(:dashboard_action, required_supports: 0, day_offset: 10)
|
||||||
|
proposal = build(:proposal, published_at: Time.current - 9.days)
|
||||||
|
|
||||||
|
expect(action).not_to be_active_for(proposal)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is not active when not enough supports' do
|
||||||
|
action = build(:dashboard_action, required_supports: 10, day_offset: 0)
|
||||||
|
proposal = build(:proposal, cached_votes_up: 9)
|
||||||
|
|
||||||
|
expect(action).not_to be_active_for(proposal)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'executed_for? and requested_for?' do
|
context 'requested_for?' do
|
||||||
let(:proposal) { create(:proposal) }
|
it 'is not requested when no administrator task' do
|
||||||
subject { create(:dashboard_action, :active, :admin_request, :resource) }
|
proposal = create(:proposal)
|
||||||
|
action = create(:dashboard_action, :active, :admin_request, :resource)
|
||||||
|
|
||||||
it { should_not be_requested_for(proposal) }
|
expect(action).not_to be_requested_for(proposal)
|
||||||
it { should_not be_executed_for(proposal) }
|
end
|
||||||
|
|
||||||
context 'and executed action' do
|
it 'is requested when administrator task' do
|
||||||
let(:executed_action) { create(:dashboard_executed_action, proposal: proposal, action: subject) }
|
proposal = create(:proposal)
|
||||||
|
action = create(:dashboard_action, :active, :admin_request, :resource)
|
||||||
|
executed_action = create(:dashboard_executed_action, proposal: proposal, action: action)
|
||||||
|
_task = create(:dashboard_administrator_task, :pending, source: executed_action)
|
||||||
|
|
||||||
context 'and pending administrator task' do
|
expect(action).to be_requested_for(proposal)
|
||||||
let!(:task) { create(:dashboard_administrator_task, :pending, source: executed_action) }
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it { should be_requested_for(proposal) }
|
context 'executed_for?' do
|
||||||
it { should_not be_executed_for(proposal) }
|
it 'is not executed when no administrator task' do
|
||||||
end
|
proposal = create(:proposal)
|
||||||
|
action = create(:dashboard_action, :active, :admin_request, :resource)
|
||||||
|
|
||||||
context 'and solved administrator task' do
|
expect(action).not_to be_executed_for(proposal)
|
||||||
let!(:task) { create(:dashboard_administrator_task, :done, source: executed_action) }
|
end
|
||||||
|
|
||||||
it { should be_requested_for(proposal) }
|
it 'is not executed when pending administrator task' do
|
||||||
it { should be_executed_for(proposal) }
|
proposal = create(:proposal)
|
||||||
end
|
action = create(:dashboard_action, :active, :admin_request, :resource)
|
||||||
|
executed_action = create(:dashboard_executed_action, proposal: proposal, action: action)
|
||||||
|
_task = create(:dashboard_administrator_task, :pending, source: executed_action)
|
||||||
|
|
||||||
|
expect(action).not_to be_executed_for(proposal)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is executed when done administrator task' do
|
||||||
|
proposal = create(:proposal)
|
||||||
|
action = create(:dashboard_action, :active, :admin_request, :resource)
|
||||||
|
executed_action = create(:dashboard_executed_action, proposal: proposal, action: action)
|
||||||
|
_task = create(:dashboard_administrator_task, :done, source: executed_action)
|
||||||
|
|
||||||
|
expect(action).to be_executed_for(proposal)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,8 @@
|
|||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe Dashboard::AdministratorTask do
|
describe Dashboard::AdministratorTask do
|
||||||
subject { build :dashboard_administrator_task, source: executed_action }
|
it 'is invalid when source is nil' do
|
||||||
let(:executed_action) { build :dashboard_executed_action }
|
task = build(:dashboard_administrator_task, source: nil)
|
||||||
|
expect(task).not_to be_valid
|
||||||
it { should be_valid }
|
|
||||||
|
|
||||||
context 'when source is nil' do
|
|
||||||
let(:executed_action) { nil }
|
|
||||||
|
|
||||||
it { should_not be_valid }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +1,29 @@
|
|||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe Dashboard::ExecutedAction do
|
describe Dashboard::ExecutedAction do
|
||||||
subject do
|
|
||||||
build :dashboard_executed_action,
|
|
||||||
proposal: proposal,
|
|
||||||
action: action,
|
|
||||||
executed_at: executed_at
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:proposal) { create :proposal }
|
let(:proposal) { create :proposal }
|
||||||
let(:action) do
|
let(:action) do
|
||||||
create :dashboard_action, request_to_administrators: request_to_administrators, link: Faker::Internet.url
|
create :dashboard_action, request_to_administrators: true, link: Faker::Internet.url
|
||||||
end
|
|
||||||
let(:request_to_administrators) { false }
|
|
||||||
let(:executed_at) { Time.current }
|
|
||||||
|
|
||||||
it { should be_valid }
|
|
||||||
|
|
||||||
context 'when proposal is nil' do
|
|
||||||
let(:proposal) { nil }
|
|
||||||
|
|
||||||
it { should_not be_valid }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when action is nil' do
|
it 'is invalid when proposal is nil' do
|
||||||
let(:action) { nil }
|
action = build(:dashboard_executed_action, proposal: nil)
|
||||||
|
expect(action).not_to be_valid
|
||||||
it { should_not be_valid }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when executed_at is nil' do
|
it 'is invalid when action is nil' do
|
||||||
let(:executed_at) { nil }
|
action = build(:dashboard_executed_action, action: nil)
|
||||||
|
expect(action).not_to be_valid
|
||||||
it { should_not be_valid }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the action sends a request to the administrators' do
|
it 'is invalid when executed_at is nil' do
|
||||||
let(:request_to_administrators) { true }
|
action = build(:dashboard_executed_action, executed_at: nil)
|
||||||
|
expect(action).not_to be_valid
|
||||||
it { should be_valid }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when it has been already executed' do
|
it 'when action has been already executed it is invalid' do
|
||||||
let!(:executed) { create(:dashboard_executed_action, proposal: proposal, action: action) }
|
_executed = create(:dashboard_executed_action, proposal: proposal, action: action)
|
||||||
|
action = build(:dashboard_executed_action, proposal: proposal, action: action)
|
||||||
it { should_not be_valid }
|
expect(action).not_to be_valid
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,29 +1,15 @@
|
|||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe Link do
|
describe Link do
|
||||||
subject do
|
let(:action) { build :dashboard_action }
|
||||||
build :link,
|
|
||||||
linkable: dashboard_action,
|
it 'is invalid when label is blank' do
|
||||||
label: label,
|
link = build(:link, linkable: action, label: '')
|
||||||
url: url,
|
expect(link).not_to be_valid
|
||||||
open_in_new_tab: true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:dashboard_action) { build :dashboard_action }
|
it 'is invalid when url is blank' do
|
||||||
let(:label) { Faker::Lorem.sentence }
|
link = build(:link, linkable: action, url: '')
|
||||||
let(:url) { Faker::Internet.url }
|
expect(link).not_to be_valid
|
||||||
|
|
||||||
it { should be_valid }
|
|
||||||
|
|
||||||
context 'when label is blank' do
|
|
||||||
let(:label) { '' }
|
|
||||||
|
|
||||||
it { should_not be_valid }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when url is blank' do
|
|
||||||
let(:url) { '' }
|
|
||||||
|
|
||||||
it { should_not be_valid }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
51
spec/requests/dashboard/achievements_spec.rb
Normal file
51
spec/requests/dashboard/achievements_spec.rb
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe "Retrieves achievements for a proposal" do
|
||||||
|
let(:created_at) { DateTime.parse("2018-01-01 12:00:00") }
|
||||||
|
let(:proposal) { create(:proposal, created_at: created_at) }
|
||||||
|
let(:executed_actions) { create_list(:dashboard_action, 8, :active, :proposed_action) }
|
||||||
|
let!(:non_executed_actions) { create_list(:dashboard_action, 8, :active, :proposed_action) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
sign_in(proposal.author)
|
||||||
|
|
||||||
|
executed_actions.each_with_index do |action, index|
|
||||||
|
create(:dashboard_executed_action, proposal: proposal, action: action, executed_at: proposal.created_at + index.days)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a list of most recent executed achievements grouped by day" do
|
||||||
|
get proposal_dashboard_achievements_path(proposal, format: :json)
|
||||||
|
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json.length).to eq(8)
|
||||||
|
|
||||||
|
executed_actions.each do |action|
|
||||||
|
expect(json.values.select { |a| a[:title] == action.title }).not_to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
non_executed_actions.each do |action|
|
||||||
|
expect(json.values.select { |a| a[:title] == action.title }).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a list of most recent executed achievements grouped by week" do
|
||||||
|
get proposal_dashboard_achievements_path(proposal, group_by: 'week', format: :json)
|
||||||
|
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json.length).to eq(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a list of most recent executed achievements grouped by month" do
|
||||||
|
get proposal_dashboard_achievements_path(proposal, group_by: 'month', format: :json)
|
||||||
|
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json.length).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
58
spec/requests/dashboard/successful_supports_spec.rb
Normal file
58
spec/requests/dashboard/successful_supports_spec.rb
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe "Retrieves number of supports for the successful proposal" do
|
||||||
|
let(:created_at) { DateTime.parse("2018-01-01 12:00:00") }
|
||||||
|
let(:proposal) { create(:proposal, created_at: created_at) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
@successful_proposal_id = Setting['proposals.successful_proposal_id']
|
||||||
|
Setting['proposals.successful_proposal_id'] = proposal.id
|
||||||
|
|
||||||
|
8.times do |i|
|
||||||
|
user = create(:user, :verified)
|
||||||
|
Vote.create!(
|
||||||
|
votable: proposal,
|
||||||
|
voter: user,
|
||||||
|
vote_weight: 1,
|
||||||
|
created_at: proposal.created_at + i.days,
|
||||||
|
updated_at: proposal.created_at + i.days
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
sign_in(proposal.author)
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
Setting['proposals.successful_proposal_id'] = @successful_proposal_id
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the number of supports grouped by day" do
|
||||||
|
get proposal_dashboard_successful_supports_path(proposal, format: :json)
|
||||||
|
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json.length).to eq(8)
|
||||||
|
expect(json.values.last).to eq(8)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the number of supports grouped by week" do
|
||||||
|
get proposal_dashboard_successful_supports_path(proposal, group_by: 'week', format: :json)
|
||||||
|
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json.length).to eq(2)
|
||||||
|
expect(json.values.last).to eq(8)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the number of supports grouped by month" do
|
||||||
|
get proposal_dashboard_successful_supports_path(proposal, group_by: 'month', format: :json)
|
||||||
|
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json.length).to eq(1)
|
||||||
|
expect(json.values.last).to eq(8)
|
||||||
|
end
|
||||||
|
end
|
||||||
45
spec/requests/dashboard/supports_spec.rb
Normal file
45
spec/requests/dashboard/supports_spec.rb
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe "Retrieves number of supports for a proposal" do
|
||||||
|
let(:created_at) { DateTime.parse("2018-01-01 12:00:00") }
|
||||||
|
let(:proposal) { create(:proposal, created_at: created_at) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
8.times do |i|
|
||||||
|
user = create(:user, :verified)
|
||||||
|
Vote.create!(votable: proposal, voter: user, vote_weight: 1, created_at: proposal.created_at + i.days, updated_at: proposal.created_at + i.days)
|
||||||
|
end
|
||||||
|
|
||||||
|
sign_in(proposal.author)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the number of supports grouped by day" do
|
||||||
|
get proposal_dashboard_supports_path(proposal, format: :json)
|
||||||
|
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json.length).to eq(8)
|
||||||
|
expect(json.values.last).to eq(8)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the number of supports grouped by week" do
|
||||||
|
get proposal_dashboard_supports_path(proposal, group_by: 'week', format: :json)
|
||||||
|
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json.length).to eq(2)
|
||||||
|
expect(json.values.last).to eq(8)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the number of supports grouped by month" do
|
||||||
|
get proposal_dashboard_supports_path(proposal, group_by: 'month', format: :json)
|
||||||
|
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json.length).to eq(1)
|
||||||
|
expect(json.values.last).to eq(8)
|
||||||
|
end
|
||||||
|
end
|
||||||
22
spec/shared/request_spec_helper.rb
Normal file
22
spec/shared/request_spec_helper.rb
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
module RequestSpecHelper
|
||||||
|
include Warden::Test::Helpers
|
||||||
|
|
||||||
|
def self.included(base)
|
||||||
|
base.before(:each) { Warden.test_mode! }
|
||||||
|
base.after(:each) { Warden.test_reset! }
|
||||||
|
end
|
||||||
|
|
||||||
|
def sign_in(resource)
|
||||||
|
login_as(resource, scope: warden_scope(resource))
|
||||||
|
end
|
||||||
|
|
||||||
|
def sign_out(resource)
|
||||||
|
logout(warden_scope(resource))
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def warden_scope(resource)
|
||||||
|
resource.class.name.underscore.to_sym
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -14,6 +14,7 @@ RSpec.configure do |config|
|
|||||||
config.filter_run :focus
|
config.filter_run :focus
|
||||||
config.run_all_when_everything_filtered = true
|
config.run_all_when_everything_filtered = true
|
||||||
config.include Devise::TestHelpers, type: :controller
|
config.include Devise::TestHelpers, type: :controller
|
||||||
|
config.include RequestSpecHelper, type: :request
|
||||||
config.include FactoryBot::Syntax::Methods
|
config.include FactoryBot::Syntax::Methods
|
||||||
config.include(EmailSpec::Helpers)
|
config.include(EmailSpec::Helpers)
|
||||||
config.include(EmailSpec::Matchers)
|
config.include(EmailSpec::Matchers)
|
||||||
|
|||||||
Reference in New Issue
Block a user