Merge branch 'master' into legislation-module-stable
This commit is contained in:
@@ -527,6 +527,3 @@ DEPENDENCIES
|
|||||||
unicorn (~> 5.2.0)
|
unicorn (~> 5.2.0)
|
||||||
web-console (= 3.3.0)
|
web-console (= 3.3.0)
|
||||||
whenever
|
whenever
|
||||||
|
|
||||||
BUNDLED WITH
|
|
||||||
1.13.6
|
|
||||||
|
|||||||
12
app/assets/javascripts/allow_participation.js.coffee
Normal file
12
app/assets/javascripts/allow_participation.js.coffee
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
App.AllowParticipation =
|
||||||
|
|
||||||
|
initialize: ->
|
||||||
|
$(document).on {
|
||||||
|
'mouseenter focus': ->
|
||||||
|
$(this).find(".js-participation-not-allowed").show();
|
||||||
|
$(this).find(".js-participation-allowed").hide();
|
||||||
|
mouseleave: ->
|
||||||
|
$(this).find(".js-participation-not-allowed").hide();
|
||||||
|
$(this).find(".js-participation-allowed").show();
|
||||||
|
}, ".js-participation"
|
||||||
|
false
|
||||||
@@ -36,12 +36,14 @@
|
|||||||
//= require tags
|
//= require tags
|
||||||
//= require users
|
//= require users
|
||||||
//= require votes
|
//= require votes
|
||||||
|
//= require allow_participation
|
||||||
//= require annotatable
|
//= require annotatable
|
||||||
//= require advanced_search
|
//= require advanced_search
|
||||||
//= require registration_form
|
//= require registration_form
|
||||||
//= require suggest
|
//= require suggest
|
||||||
//= require forms
|
//= require forms
|
||||||
//= require tracks
|
//= require tracks
|
||||||
|
//= require valuation_budget_investment_form
|
||||||
//= require valuation_spending_proposal_form
|
//= require valuation_spending_proposal_form
|
||||||
//= require embed_video
|
//= require embed_video
|
||||||
//= require banners
|
//= require banners
|
||||||
@@ -58,6 +60,7 @@ var initialize_modules = function() {
|
|||||||
App.Comments.initialize();
|
App.Comments.initialize();
|
||||||
App.Users.initialize();
|
App.Users.initialize();
|
||||||
App.Votes.initialize();
|
App.Votes.initialize();
|
||||||
|
App.AllowParticipation.initialize();
|
||||||
App.Tags.initialize();
|
App.Tags.initialize();
|
||||||
App.Dropdown.initialize();
|
App.Dropdown.initialize();
|
||||||
App.LocationChanger.initialize();
|
App.LocationChanger.initialize();
|
||||||
@@ -70,6 +73,7 @@ var initialize_modules = function() {
|
|||||||
App.Suggest.initialize();
|
App.Suggest.initialize();
|
||||||
App.Forms.initialize();
|
App.Forms.initialize();
|
||||||
App.Tracks.initialize();
|
App.Tracks.initialize();
|
||||||
|
App.ValuationBudgetInvestmentForm.initialize();
|
||||||
App.ValuationSpendingProposalForm.initialize();
|
App.ValuationSpendingProposalForm.initialize();
|
||||||
App.EmbedVideo.initialize();
|
App.EmbedVideo.initialize();
|
||||||
App.Banners.initialize();
|
App.Banners.initialize();
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
App.ValuationBudgetInvestmentForm =
|
||||||
|
|
||||||
|
showFeasibleFields: ->
|
||||||
|
$('#valuation_budget_investment_edit_form #unfeasible_fields').hide('down')
|
||||||
|
$('#valuation_budget_investment_edit_form #feasible_fields').show()
|
||||||
|
|
||||||
|
showNotFeasibleFields: ->
|
||||||
|
$('#valuation_budget_investment_edit_form #feasible_fields').hide('down')
|
||||||
|
$('#valuation_budget_investment_edit_form #unfeasible_fields').show()
|
||||||
|
|
||||||
|
showAllFields: ->
|
||||||
|
$('#valuation_budget_investment_edit_form #feasible_fields').show('down')
|
||||||
|
$('#valuation_budget_investment_edit_form #unfeasible_fields').show('down')
|
||||||
|
|
||||||
|
showFeasibilityFields: ->
|
||||||
|
feasibility = $("#valuation_budget_investment_edit_form input[type=radio][name='budget_investment[feasibility]']:checked").val()
|
||||||
|
if feasibility == 'feasible'
|
||||||
|
App.ValuationBudgetInvestmentForm.showFeasibleFields()
|
||||||
|
else if feasibility == 'unfeasible'
|
||||||
|
App.ValuationBudgetInvestmentForm.showNotFeasibleFields()
|
||||||
|
|
||||||
|
|
||||||
|
showFeasibilityFieldsOnChange: ->
|
||||||
|
$("#valuation_budget_investment_edit_form input[type=radio][name='budget_investment[feasibility]']").change ->
|
||||||
|
App.ValuationBudgetInvestmentForm.showAllFields()
|
||||||
|
App.ValuationBudgetInvestmentForm.showFeasibilityFields()
|
||||||
|
|
||||||
|
|
||||||
|
initialize: ->
|
||||||
|
App.ValuationBudgetInvestmentForm.showFeasibilityFields()
|
||||||
|
App.ValuationBudgetInvestmentForm.showFeasibilityFieldsOnChange()
|
||||||
|
false
|
||||||
@@ -76,7 +76,7 @@ $check: #46DB91;
|
|||||||
$proposals: #FFA42D;
|
$proposals: #FFA42D;
|
||||||
$proposals-dark: #794500;
|
$proposals-dark: #794500;
|
||||||
|
|
||||||
$budget: #454372;
|
$budget: #7E328A;
|
||||||
$budget-hover: #7571BF;
|
$budget-hover: #7571BF;
|
||||||
|
|
||||||
$highlight: #E7F2FC;
|
$highlight: #E7F2FC;
|
||||||
|
|||||||
@@ -37,12 +37,21 @@ body.admin {
|
|||||||
input[type="text"], textarea {
|
input[type="text"], textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input-group input[type="text"] {
|
||||||
|
border-radius: 0;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
|
|
||||||
th {
|
th {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
||||||
|
&.with-button {
|
||||||
|
line-height: $line-height*2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tr {
|
tr {
|
||||||
@@ -376,7 +385,7 @@ body.admin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-content .select-geozone {
|
.admin-content .select-geozone, .admin-content .select-heading {
|
||||||
|
|
||||||
a {
|
a {
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
@@ -180,6 +180,9 @@
|
|||||||
.icon-arrow-top:before {
|
.icon-arrow-top:before {
|
||||||
content: "\57";
|
content: "\57";
|
||||||
}
|
}
|
||||||
|
.icon-help-1:before {
|
||||||
|
content: "\58";
|
||||||
|
}
|
||||||
.icon-checkmark-circle:before {
|
.icon-checkmark-circle:before {
|
||||||
content: "\59";
|
content: "\59";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -600,12 +600,28 @@ h2.sidebar-title {
|
|||||||
// --------------
|
// --------------
|
||||||
|
|
||||||
.auth-page {
|
.auth-page {
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
margin: 0 auto (-$line-height)*14;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-image {
|
||||||
background: $brand image-url("auth_bg.jpg");
|
background: $brand image-url("auth_bg.jpg");
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
|
|
||||||
h1:not(.logo) {
|
@include breakpoint(medium) {
|
||||||
@include logo;
|
min-height: $line-height*42;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-top: $line-height;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: rem-calc(80);
|
||||||
|
width: rem-calc(80);
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: white;
|
color: white;
|
||||||
@@ -621,15 +637,27 @@ h2.sidebar-title {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth {
|
.auth-form {
|
||||||
|
|
||||||
|
@include breakpoint(medium) {
|
||||||
|
padding-top: $line-height*4;
|
||||||
|
}
|
||||||
|
|
||||||
p, a, .checkbox {
|
p, a, .checkbox {
|
||||||
font-size: $small-font-size;
|
font-size: $small-font-size;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.panel {
|
.auth-divider {
|
||||||
|
border-bottom: 1px solid $border;
|
||||||
|
height: $line-height/2;
|
||||||
|
margin: $line-height 0;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
span {
|
||||||
background: white;
|
background: white;
|
||||||
border: 0;
|
font-weight: bold;
|
||||||
|
padding: 0 $line-height/2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -805,6 +833,11 @@ form {
|
|||||||
.callout {
|
.callout {
|
||||||
font-size: $small-font-size;
|
font-size: $small-font-size;
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: bold;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
&.success, &.notice {
|
&.success, &.notice {
|
||||||
background-color: $success-bg;
|
background-color: $success-bg;
|
||||||
border-color: $success-border;
|
border-color: $success-border;
|
||||||
@@ -821,12 +854,6 @@ form {
|
|||||||
background-color: $warning-bg;
|
background-color: $warning-bg;
|
||||||
border-color: $warning-border;
|
border-color: $warning-border;
|
||||||
color: $color-warning;
|
color: $color-warning;
|
||||||
|
|
||||||
a {
|
|
||||||
color: $color-warning;
|
|
||||||
font-weight: bold;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.alert, &.error {
|
&.alert, &.error {
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
// 03. Show participation
|
// 03. Show participation
|
||||||
// 04. List participation
|
// 04. List participation
|
||||||
// 05. Featured
|
// 05. Featured
|
||||||
// 06. Proposals successfull
|
// 06. Budget
|
||||||
|
// 07. Proposals successfull
|
||||||
//
|
//
|
||||||
|
|
||||||
// 01. Votes and supports
|
// 01. Votes and supports
|
||||||
@@ -238,6 +239,7 @@
|
|||||||
|
|
||||||
.debate-form,
|
.debate-form,
|
||||||
.proposal-form,
|
.proposal-form,
|
||||||
|
.budget-investment-form,
|
||||||
.spending-proposal-form {
|
.spending-proposal-form {
|
||||||
|
|
||||||
.icon-debates, .icon-proposals, .icon-budget {
|
.icon-debates, .icon-proposals, .icon-budget {
|
||||||
@@ -295,7 +297,8 @@
|
|||||||
.debate-show,
|
.debate-show,
|
||||||
.proposal-show,
|
.proposal-show,
|
||||||
.investment-project-show,
|
.investment-project-show,
|
||||||
.debate-quiz {
|
.debate-quiz,
|
||||||
|
.budget-investment-show {
|
||||||
|
|
||||||
p {
|
p {
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
@@ -322,14 +325,14 @@
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.debate-info, .proposal-info, .investment-project-info {
|
.debate-info, .proposal-info, .investment-project-info, .budget-investment-show {
|
||||||
clear: both;
|
clear: both;
|
||||||
color: $text-medium;
|
color: $text-medium;
|
||||||
font-size: $small-font-size;
|
font-size: $small-font-size;
|
||||||
margin-bottom: $line-height/2;
|
margin-bottom: $line-height/2;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
span {
|
span:not(.label) {
|
||||||
line-height: rem-calc(32); // Same as avatar height
|
line-height: rem-calc(32); // Same as avatar height
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,11 +459,11 @@
|
|||||||
color: $border;
|
color: $border;
|
||||||
}
|
}
|
||||||
|
|
||||||
.investment-project-show p {
|
.investment-project-show p, .budget-investment-show p {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.proposal-show, .investment-project-show {
|
.proposal-show, .investment-project-show, .budget-investment-show {
|
||||||
|
|
||||||
.supports {
|
.supports {
|
||||||
padding: $line-height/2 0 0;
|
padding: $line-height/2 0 0;
|
||||||
@@ -474,21 +477,21 @@
|
|||||||
// 04. List participation
|
// 04. List participation
|
||||||
// ----------------------
|
// ----------------------
|
||||||
|
|
||||||
.debates-list, .proposals-list, .investment-projects-list {
|
.debates-list, .proposals-list, .investment-projects-list, .budget-investments-list {
|
||||||
|
|
||||||
@include breakpoint(medium) {
|
@include breakpoint(medium) {
|
||||||
margin-bottom: rem-calc(48);
|
margin-bottom: rem-calc(48);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.investment-projects-list {
|
.investment-projects-list, .budget-investments-list {
|
||||||
|
|
||||||
@include breakpoint(medium) {
|
@include breakpoint(medium) {
|
||||||
min-height: $line-height*15;
|
min-height: $line-height*15;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.debate, .proposal, .investment-project, .legislation {
|
.debate, .proposal, .investment-project, .budget-investment, .legislation {
|
||||||
margin: $line-height/4 0;
|
margin: $line-height/4 0;
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
@@ -506,7 +509,7 @@
|
|||||||
padding-bottom: rem-calc(12);
|
padding-bottom: rem-calc(12);
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-debate, .label-proposal, .label-investment-project {
|
.label-debate, .label-proposal, .label-investment-project, .label-budget-investment {
|
||||||
background: none;
|
background: none;
|
||||||
clear: both;
|
clear: both;
|
||||||
display: block;
|
display: block;
|
||||||
@@ -531,6 +534,10 @@
|
|||||||
color: $budget;
|
color: $budget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.label-budget-investment {
|
||||||
|
color: $budget;
|
||||||
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -540,7 +547,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.debate-content, .proposal-content, .investment-project-content {
|
.debate-content, .proposal-content, .investment-project-content, .budget-investment-content {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
min-height: rem-calc(180);
|
min-height: rem-calc(180);
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -570,7 +577,7 @@
|
|||||||
font-size: $small-font-size;
|
font-size: $small-font-size;
|
||||||
}
|
}
|
||||||
|
|
||||||
.debate-info, .proposal-info, .investment-project-info {
|
.debate-info, .proposal-info, .investment-project-info, .budget-investment-info {
|
||||||
color: $text-medium;
|
color: $text-medium;
|
||||||
font-size: $small-font-size;
|
font-size: $small-font-size;
|
||||||
margin: rem-calc(6) 0 0;
|
margin: rem-calc(6) 0 0;
|
||||||
@@ -585,7 +592,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.debate-description, .proposal-description, .investment-project-description {
|
.debate-description, .proposal-description, .investment-project-description, .budget-investment-description {
|
||||||
color: $text;
|
color: $text;
|
||||||
font-size: rem-calc(13);
|
font-size: rem-calc(13);
|
||||||
height: rem-calc(72);
|
height: rem-calc(72);
|
||||||
@@ -670,12 +677,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.investment-project, .investment-project-show {
|
.investment-project, .investment-project-show,
|
||||||
|
.budget-investment, .budget-investment-show {
|
||||||
|
|
||||||
.supports {
|
.supports {
|
||||||
@include supports;
|
@include supports;
|
||||||
|
|
||||||
.investment-project-amount {
|
.investment-project-amount,
|
||||||
|
.budget-investment-amount {
|
||||||
color: $budget;
|
color: $budget;
|
||||||
font-size: rem-calc(20);
|
font-size: rem-calc(20);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -704,6 +713,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.remove .icon-check-circle {
|
.remove .icon-check-circle {
|
||||||
|
color: $budget;
|
||||||
display: block;
|
display: block;
|
||||||
font-size: rem-calc(70);
|
font-size: rem-calc(70);
|
||||||
line-height: rem-calc(70);
|
line-height: rem-calc(70);
|
||||||
@@ -711,6 +721,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.investment-project-show .supports,
|
||||||
|
.budget-investment-show .supports {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.proposals-summary {
|
.proposals-summary {
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
@@ -719,11 +734,38 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.investment-project .supports .total-supports.no-button,
|
.investment-project .supports .total-supports.no-button,
|
||||||
.investment-project-show .supports .total-supports.no-button {
|
.investment-project-show .supports .total-supports.no-button,
|
||||||
|
.budget-investment .supports .total-supports.no-button,
|
||||||
|
.budget-investment-show .supports .total-supports.no-button {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: $line-height*1.5;
|
margin-top: $line-height*1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.budget-investment-show {
|
||||||
|
|
||||||
|
.label-budget-investment {
|
||||||
|
background: none;
|
||||||
|
clear: both;
|
||||||
|
color: $budget;
|
||||||
|
display: block;
|
||||||
|
font-size: rem-calc(12);
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: $line-height;
|
||||||
|
padding-bottom: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-budget {
|
||||||
|
color: $budget;
|
||||||
|
font-size: $small-font-size;
|
||||||
|
line-height: $line-height;
|
||||||
|
margin-left: rem-calc(6);
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 05. Featured
|
// 05. Featured
|
||||||
// ------------
|
// ------------
|
||||||
|
|
||||||
@@ -835,7 +877,281 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 06. Proposals successfull
|
// 06. Budget
|
||||||
|
// ----------
|
||||||
|
|
||||||
|
.expanded.budget {
|
||||||
|
background: $budget;
|
||||||
|
|
||||||
|
h1, h2, p, a.back, .icon-angle-left {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
background: white;
|
||||||
|
color: $budget;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
background: #6A2A72;
|
||||||
|
|
||||||
|
@include breakpoint(medium) {
|
||||||
|
border-top: rem-calc(6) solid #54225C;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.jumbo-budget {
|
||||||
|
background: $budget;
|
||||||
|
border-bottom: 1px solid $budget;
|
||||||
|
|
||||||
|
&.budget-heading {
|
||||||
|
min-height: $line-height*10;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, .back, .icon-angle-left, p, a {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.welcome {
|
||||||
|
background: $budget image-url('spending_proposals_bg.jpg');
|
||||||
|
background-position: 50% 50%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
|
||||||
|
.spending-proposal-timeline {
|
||||||
|
padding-top: $line-height;
|
||||||
|
|
||||||
|
ul li {
|
||||||
|
margin-right: $line-height;
|
||||||
|
padding-top: $line-height/2;
|
||||||
|
|
||||||
|
.icon-calendar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
&.button {
|
||||||
|
background: white;
|
||||||
|
color: $brand;
|
||||||
|
margin-bottom: rem-calc(3);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-share-button a {
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
&.social-share-button-twitter:hover {
|
||||||
|
color: #40A2D1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.social-share-button-facebook:hover {
|
||||||
|
color: #354F88;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.social-share-button-google_plus:hover {
|
||||||
|
color: #CE3E26;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-votes {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
background: #212033;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-meter {
|
||||||
|
background: #fdcb10;
|
||||||
|
border-radius: 0;
|
||||||
|
-webkit-transition: width 2s;
|
||||||
|
transition: width 2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spent-amount-progress,
|
||||||
|
.spent-amount-meter {
|
||||||
|
background: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spent-amount-text {
|
||||||
|
color: white;
|
||||||
|
font-size: $base-font-size;
|
||||||
|
font-weight: normal;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
text-align: right;
|
||||||
|
top: 16px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
color: #a5a1ff;
|
||||||
|
content: "\57";
|
||||||
|
font-family: 'icons';
|
||||||
|
font-size: $small-font-size;
|
||||||
|
position: absolute;
|
||||||
|
right: -6px;
|
||||||
|
top: -17px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.total-amount {
|
||||||
|
color: white;
|
||||||
|
font-size: rem-calc(18);
|
||||||
|
font-weight: bold;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-available {
|
||||||
|
display: block;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: rem-calc(24);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.big-number {
|
||||||
|
color: $budget;
|
||||||
|
font-size: rem-calc(60);
|
||||||
|
line-height: rem-calc(120);
|
||||||
|
|
||||||
|
@include breakpoint(large) {
|
||||||
|
font-size: rem-calc(90);
|
||||||
|
line-height: rem-calc(240);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ballot {
|
||||||
|
|
||||||
|
h2, h3 {
|
||||||
|
font-weight: normal;
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: $budget;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h3.subtitle {
|
||||||
|
border-bottom: 3px solid $budget;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: $base-font-size;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-spent {
|
||||||
|
background: $success-bg;
|
||||||
|
font-weight: normal;
|
||||||
|
padding: $line-height/2;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: rem-calc(24);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.ballot-list {
|
||||||
|
list-style: none;
|
||||||
|
margin-left: 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
background: #f9f9f9;
|
||||||
|
line-height: $line-height;
|
||||||
|
margin-bottom: $line-height/4;
|
||||||
|
padding: $line-height/2;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #9f9f9f;
|
||||||
|
display: block;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-investment-project {
|
||||||
|
display: block;
|
||||||
|
height: 0;
|
||||||
|
|
||||||
|
.icon-x {
|
||||||
|
color: #9f9f9f;
|
||||||
|
font-size: rem-calc(24);
|
||||||
|
line-height: $line-height/2;
|
||||||
|
position: absolute;
|
||||||
|
right: 6px;
|
||||||
|
text-decoration: none;
|
||||||
|
top: 6px;
|
||||||
|
|
||||||
|
@include breakpoint(medium) {
|
||||||
|
font-size: $base-font-size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $budget;
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
a, span {
|
||||||
|
color: white;
|
||||||
|
outline: 0;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-investment-project .icon-x {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-district a {
|
||||||
|
display: inline-block;
|
||||||
|
margin: $line-height/4 0;
|
||||||
|
padding: $line-height/4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-district .active a {
|
||||||
|
background: #f9f9f9;
|
||||||
|
border-radius: rem-calc(3);
|
||||||
|
color: $budget;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: "\56";
|
||||||
|
font-family: "icons";
|
||||||
|
font-size: $small-font-size;
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: $line-height;
|
||||||
|
padding-left: rem-calc(3);
|
||||||
|
vertical-align: baseline;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 07. Proposals successfull
|
||||||
// -------------------------
|
// -------------------------
|
||||||
|
|
||||||
.dark-heading {
|
.dark-heading {
|
||||||
|
|||||||
17
app/controllers/admin/budget_groups_controller.rb
Normal file
17
app/controllers/admin/budget_groups_controller.rb
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
class Admin::BudgetGroupsController < Admin::BaseController
|
||||||
|
include FeatureFlags
|
||||||
|
feature_flag :budgets
|
||||||
|
|
||||||
|
def create
|
||||||
|
@budget = Budget.find params[:budget_id]
|
||||||
|
@budget.groups.create(budget_group_params)
|
||||||
|
@groups = @budget.groups.includes(:headings)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def budget_group_params
|
||||||
|
params.require(:budget_group).permit(:name)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
18
app/controllers/admin/budget_headings_controller.rb
Normal file
18
app/controllers/admin/budget_headings_controller.rb
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
class Admin::BudgetHeadingsController < Admin::BaseController
|
||||||
|
include FeatureFlags
|
||||||
|
feature_flag :budgets
|
||||||
|
|
||||||
|
def create
|
||||||
|
@budget = Budget.find params[:budget_id]
|
||||||
|
@budget_group = @budget.groups.find params[:budget_group_id]
|
||||||
|
@budget_group.headings.create(budget_heading_params)
|
||||||
|
@headings = @budget_group.headings
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def budget_heading_params
|
||||||
|
params.require(:budget_heading).permit(:name, :price, :geozone_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
86
app/controllers/admin/budget_investments_controller.rb
Normal file
86
app/controllers/admin/budget_investments_controller.rb
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
class Admin::BudgetInvestmentsController < Admin::BaseController
|
||||||
|
include FeatureFlags
|
||||||
|
feature_flag :budgets
|
||||||
|
|
||||||
|
has_filters(%w{valuation_open without_admin managed valuating valuation_finished
|
||||||
|
valuation_finished_feasible selected all},
|
||||||
|
only: [:index, :toggle_selection])
|
||||||
|
|
||||||
|
before_action :load_budget
|
||||||
|
before_action :load_investment, only: [:show, :edit, :update, :toggle_selection]
|
||||||
|
before_action :load_ballot, only: [:show, :index]
|
||||||
|
before_action :load_investments, only: [:index, :toggle_selection]
|
||||||
|
|
||||||
|
def index
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
load_admins
|
||||||
|
load_valuators
|
||||||
|
load_tags
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
set_valuation_tags
|
||||||
|
if @investment.update(budget_investment_params)
|
||||||
|
redirect_to admin_budget_budget_investment_path(@budget, @investment, Budget::Investment.filter_params(params)),
|
||||||
|
notice: t("flash.actions.update.budget_investment")
|
||||||
|
else
|
||||||
|
load_admins
|
||||||
|
load_valuators
|
||||||
|
load_tags
|
||||||
|
render :edit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def toggle_selection
|
||||||
|
@investment.toggle :selected
|
||||||
|
@investment.save
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_investments
|
||||||
|
@investments = Budget::Investment.scoped_filter(params, @current_filter)
|
||||||
|
.order(cached_votes_up: :desc, created_at: :desc)
|
||||||
|
.page(params[:page])
|
||||||
|
end
|
||||||
|
|
||||||
|
def budget_investment_params
|
||||||
|
params.require(:budget_investment)
|
||||||
|
.permit(:title, :description, :external_url, :heading_id, :administrator_id, :valuation_tag_list, valuator_ids: [])
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_budget
|
||||||
|
@budget = Budget.includes(:groups).find params[:budget_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_investment
|
||||||
|
@investment = Budget::Investment.where(budget_id: @budget.id).find params[:id]
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_admins
|
||||||
|
@admins = Administrator.includes(:user).all
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_valuators
|
||||||
|
@valuators = Valuator.includes(:user).all.order("description ASC").order("users.email ASC")
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_tags
|
||||||
|
@tags = Budget::Investment.tags_on(:valuation).order(:name).uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_ballot
|
||||||
|
query = Budget::Ballot.where(user: current_user, budget: @budget)
|
||||||
|
@ballot = @budget.balloting? ? query.first_or_create : query.first_or_initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_valuation_tags
|
||||||
|
@investment.set_tag_list_on(:valuation, budget_investment_params[:valuation_tag_list])
|
||||||
|
params[:budget_investment] = params[:budget_investment].except(:valuation_tag_list)
|
||||||
|
end
|
||||||
|
end
|
||||||
48
app/controllers/admin/budgets_controller.rb
Normal file
48
app/controllers/admin/budgets_controller.rb
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
class Admin::BudgetsController < Admin::BaseController
|
||||||
|
include FeatureFlags
|
||||||
|
feature_flag :budgets
|
||||||
|
|
||||||
|
has_filters %w{current finished}, only: :index
|
||||||
|
|
||||||
|
load_and_authorize_resource
|
||||||
|
|
||||||
|
def index
|
||||||
|
@budgets = Budget.send(@current_filter).order(created_at: :desc).page(params[:page])
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
@budget = Budget.includes(groups: :headings).find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
if @budget.update(budget_params)
|
||||||
|
redirect_to admin_budget_path(@budget), notice: t('admin.budgets.update.notice')
|
||||||
|
else
|
||||||
|
render :edit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@budget = Budget.new(budget_params)
|
||||||
|
if @budget.save
|
||||||
|
redirect_to admin_budget_path(@budget), notice: t('admin.budgets.create.notice')
|
||||||
|
else
|
||||||
|
render :new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def budget_params
|
||||||
|
descriptions = Budget::PHASES.map{|p| "description_#{p}"}.map(&:to_sym)
|
||||||
|
valid_attributes = [:name, :phase, :currency_symbol] + descriptions
|
||||||
|
params.require(:budget).permit(*valid_attributes)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
68
app/controllers/budgets/ballot/lines_controller.rb
Normal file
68
app/controllers/budgets/ballot/lines_controller.rb
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
module Budgets
|
||||||
|
module Ballot
|
||||||
|
class LinesController < ApplicationController
|
||||||
|
before_action :authenticate_user!
|
||||||
|
#before_action :ensure_final_voting_allowed
|
||||||
|
before_action :load_budget
|
||||||
|
before_action :load_ballot
|
||||||
|
|
||||||
|
before_action :load_investments
|
||||||
|
|
||||||
|
load_and_authorize_resource :budget
|
||||||
|
load_and_authorize_resource :ballot, class: "Budget::Ballot", through: :budget
|
||||||
|
load_and_authorize_resource :line, through: :ballot, find_by: :investment_id, class: "Budget::Ballot::Line"
|
||||||
|
|
||||||
|
def create
|
||||||
|
load_investment
|
||||||
|
load_heading
|
||||||
|
|
||||||
|
unless @ballot.add_investment(@investment)
|
||||||
|
head :bad_request
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@investment = @line.investment
|
||||||
|
load_heading
|
||||||
|
|
||||||
|
@line.destroy
|
||||||
|
load_investments
|
||||||
|
#@ballot.reset_geozone
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def ensure_final_voting_allowed
|
||||||
|
return head(:forbidden) unless @budget.balloting?
|
||||||
|
end
|
||||||
|
|
||||||
|
def line_params
|
||||||
|
params.permit(:investment_id, :budget_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_budget
|
||||||
|
@budget = Budget.find(params[:budget_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_ballot
|
||||||
|
@ballot = Budget::Ballot.where(user: current_user, budget: @budget).first_or_create
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_investment
|
||||||
|
@investment = Budget::Investment.find(params[:investment_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_investments
|
||||||
|
if params[:investments_ids].present?
|
||||||
|
@investment_ids = params[:investment_ids]
|
||||||
|
@investments = Budget::Investment.where(id: params[:investments_ids])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_heading
|
||||||
|
@heading = @investment.heading
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
20
app/controllers/budgets/ballots_controller.rb
Normal file
20
app/controllers/budgets/ballots_controller.rb
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
module Budgets
|
||||||
|
class BallotsController < ApplicationController
|
||||||
|
before_action :authenticate_user!
|
||||||
|
load_and_authorize_resource :budget
|
||||||
|
before_action :load_ballot
|
||||||
|
|
||||||
|
def show
|
||||||
|
authorize! :show, @ballot
|
||||||
|
render template: "budgets/ballot/show"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_ballot
|
||||||
|
query = Budget::Ballot.where(user: current_user, budget: @budget)
|
||||||
|
@ballot = @budget.balloting? ? query.first_or_create : query.first_or_initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
10
app/controllers/budgets/groups_controller.rb
Normal file
10
app/controllers/budgets/groups_controller.rb
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
module Budgets
|
||||||
|
class GroupsController < ApplicationController
|
||||||
|
load_and_authorize_resource :budget
|
||||||
|
load_and_authorize_resource :group, class: "Budget::Group"
|
||||||
|
|
||||||
|
def show
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
106
app/controllers/budgets/investments_controller.rb
Normal file
106
app/controllers/budgets/investments_controller.rb
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
module Budgets
|
||||||
|
class InvestmentsController < ApplicationController
|
||||||
|
include FeatureFlags
|
||||||
|
include CommentableActions
|
||||||
|
include FlagActions
|
||||||
|
|
||||||
|
before_action :authenticate_user!, except: [:index, :show]
|
||||||
|
|
||||||
|
load_and_authorize_resource :budget
|
||||||
|
load_and_authorize_resource :investment, through: :budget, class: "Budget::Investment"
|
||||||
|
|
||||||
|
before_action -> { flash.now[:notice] = flash[:notice].html_safe if flash[:html_safe] && flash[:notice] }
|
||||||
|
before_action :load_ballot, only: [:index, :show]
|
||||||
|
before_action :load_heading, only: [:index, :show]
|
||||||
|
before_action :set_random_seed, only: :index
|
||||||
|
before_action :load_categories, only: [:index, :new, :create]
|
||||||
|
|
||||||
|
feature_flag :budgets
|
||||||
|
|
||||||
|
has_orders %w{most_voted newest oldest}, only: :show
|
||||||
|
has_orders ->(c) { c.instance_variable_get(:@budget).investments_orders }, only: :index
|
||||||
|
|
||||||
|
invisible_captcha only: [:create, :update], honeypot: :subtitle, scope: :budget_investment
|
||||||
|
|
||||||
|
respond_to :html, :js
|
||||||
|
|
||||||
|
def index
|
||||||
|
@investments = @investments.apply_filters_and_search(@budget, params).send("sort_by_#{@current_order}").page(params[:page]).per(10).for_render
|
||||||
|
@investment_ids = @investments.pluck(:id)
|
||||||
|
load_investment_votes(@investments)
|
||||||
|
@tag_cloud = tag_cloud
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
@commentable = @investment
|
||||||
|
@comment_tree = CommentTree.new(@commentable, params[:page], @current_order)
|
||||||
|
set_comment_flags(@comment_tree.comments)
|
||||||
|
load_investment_votes(@investment)
|
||||||
|
@investment_ids = [@investment.id]
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@investment.author = current_user
|
||||||
|
|
||||||
|
if @investment.save
|
||||||
|
redirect_to budget_investment_path(@budget, @investment),
|
||||||
|
notice: t('flash.actions.create.budget_investment')
|
||||||
|
else
|
||||||
|
render :new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
investment.destroy
|
||||||
|
redirect_to user_path(current_user, filter: 'budget_investments'), notice: t('flash.actions.destroy.budget_investment')
|
||||||
|
end
|
||||||
|
|
||||||
|
def vote
|
||||||
|
@investment.register_selection(current_user)
|
||||||
|
load_investment_votes(@investment)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_investment_votes(investments)
|
||||||
|
@investment_votes = current_user ? current_user.budget_investment_votes(investments) : {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_random_seed
|
||||||
|
if params[:order] == 'random' || params[:order].blank?
|
||||||
|
params[:random_seed] ||= rand(99)/100.0
|
||||||
|
Budget::Investment.connection.execute "select setseed(#{params[:random_seed]})"
|
||||||
|
else
|
||||||
|
params[:random_seed] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def investment_params
|
||||||
|
params.require(:budget_investment).permit(:title, :description, :external_url, :heading_id, :tag_list, :organization_name, :location, :terms_of_service)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_ballot
|
||||||
|
query = Budget::Ballot.where(user: current_user, budget: @budget)
|
||||||
|
@ballot = @budget.balloting? ? query.first_or_create : query.first_or_initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_heading
|
||||||
|
if params[:heading_id].present?
|
||||||
|
@heading = @budget.headings.find(params[:heading_id])
|
||||||
|
@assigned_heading = @ballot.try(:heading_for_group, @heading.try(:group))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_categories
|
||||||
|
@categories = ActsAsTaggableOn::Tag.where("kind = 'category'").order(:name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def tag_cloud
|
||||||
|
TagCloud.new(Budget::Investment, params[:search])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
16
app/controllers/budgets_controller.rb
Normal file
16
app/controllers/budgets_controller.rb
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
class BudgetsController < ApplicationController
|
||||||
|
include FeatureFlags
|
||||||
|
feature_flag :budgets
|
||||||
|
|
||||||
|
|
||||||
|
load_and_authorize_resource
|
||||||
|
respond_to :html, :js
|
||||||
|
|
||||||
|
def show
|
||||||
|
end
|
||||||
|
|
||||||
|
def index
|
||||||
|
@budgets = @budgets.order(:created_at)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -3,8 +3,9 @@ module HasOrders
|
|||||||
|
|
||||||
class_methods do
|
class_methods do
|
||||||
def has_orders(valid_orders, *args)
|
def has_orders(valid_orders, *args)
|
||||||
before_action(*args) do
|
before_action(*args) do |c|
|
||||||
@valid_orders = valid_orders
|
@valid_orders = valid_orders.respond_to?(:call) ? valid_orders.call(c) : valid_orders.dup
|
||||||
|
@valid_orders.delete('relevance') if params[:search].blank?
|
||||||
@current_order = @valid_orders.include?(params[:order]) ? params[:order] : @valid_orders.first
|
@current_order = @valid_orders.include?(params[:order]) ? params[:order] : @valid_orders.first
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
66
app/controllers/management/budgets/investments_controller.rb
Normal file
66
app/controllers/management/budgets/investments_controller.rb
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
class Management::Budgets::InvestmentsController < Management::BaseController
|
||||||
|
|
||||||
|
load_resource :budget
|
||||||
|
load_resource :investment, through: :budget, class: 'Budget::Investment'
|
||||||
|
|
||||||
|
before_action :only_verified_users, except: :print
|
||||||
|
before_action :load_heading, only: [:index, :show, :print]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@investments = @investments.apply_filters_and_search(@budget, params).page(params[:page])
|
||||||
|
load_investment_votes(@investments)
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
load_categories
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@investment.terms_of_service = "1"
|
||||||
|
@investment.author = managed_user
|
||||||
|
|
||||||
|
if @investment.save
|
||||||
|
notice= t('flash.actions.create.notice', resource_name: Budget::Investment.model_name.human, count: 1)
|
||||||
|
redirect_to management_budget_investment_path(@budget, @investment), notice: notice
|
||||||
|
else
|
||||||
|
render :new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
load_investment_votes(@investment)
|
||||||
|
end
|
||||||
|
|
||||||
|
def vote
|
||||||
|
@investment.register_selection(managed_user)
|
||||||
|
load_investment_votes(@investment)
|
||||||
|
end
|
||||||
|
|
||||||
|
def print
|
||||||
|
@investments = @investments.apply_filters_and_search(@budget, params).order(cached_votes_up: :desc).for_render.limit(15)
|
||||||
|
load_investment_votes(@investments)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_investment_votes(investments)
|
||||||
|
@investment_votes = managed_user ? managed_user.budget_investment_votes(investments) : {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def investment_params
|
||||||
|
params.require(:budget_investment).permit(:title, :description, :external_url, :heading_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def only_verified_users
|
||||||
|
check_verified_user t("management.budget_investments.alert.unverified_user")
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_heading
|
||||||
|
@heading = @budget.headings.find(params[:heading_id]) if params[:heading_id].present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_categories
|
||||||
|
@categories = ActsAsTaggableOn::Tag.where("kind = 'category'").order(:name)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
26
app/controllers/management/budgets_controller.rb
Normal file
26
app/controllers/management/budgets_controller.rb
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
class Management::BudgetsController < Management::BaseController
|
||||||
|
include FeatureFlags
|
||||||
|
include HasFilters
|
||||||
|
feature_flag :budgets
|
||||||
|
|
||||||
|
before_action :only_verified_users, except: :print_investments
|
||||||
|
|
||||||
|
def create_investments
|
||||||
|
@budgets = Budget.accepting.order(created_at: :desc).page(params[:page])
|
||||||
|
end
|
||||||
|
|
||||||
|
def support_investments
|
||||||
|
@budgets = Budget.selecting.order(created_at: :desc).page(params[:page])
|
||||||
|
end
|
||||||
|
|
||||||
|
def print_investments
|
||||||
|
@budgets = Budget.current.order(created_at: :desc).page(params[:page])
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def only_verified_users
|
||||||
|
check_verified_user t("management.budget_investments.alert.unverified_user")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
class UsersController < ApplicationController
|
class UsersController < ApplicationController
|
||||||
has_filters %w{proposals debates comments spending_proposals}, only: :show
|
has_filters %w{proposals debates budget_investments comments}, only: :show
|
||||||
|
|
||||||
load_and_authorize_resource
|
load_and_authorize_resource
|
||||||
helper_method :authorized_for_filter?
|
|
||||||
helper_method :author?
|
helper_method :author?
|
||||||
helper_method :author_or_admin?
|
helper_method :author_or_admin?
|
||||||
|
|
||||||
@@ -14,9 +13,9 @@ class UsersController < ApplicationController
|
|||||||
def set_activity_counts
|
def set_activity_counts
|
||||||
@activity_counts = HashWithIndifferentAccess.new(
|
@activity_counts = HashWithIndifferentAccess.new(
|
||||||
proposals: Proposal.where(author_id: @user.id).count,
|
proposals: Proposal.where(author_id: @user.id).count,
|
||||||
debates: Debate.where(author_id: @user.id).count,
|
debates: (Setting['feature.debates'] ? Debate.where(author_id: @user.id).count : 0),
|
||||||
comments: Comment.not_as_admin_or_moderator.where(user_id: @user.id).count,
|
budget_investments: (Setting['feature.budgets'] ? Budget::Investment.where(author_id: @user.id).count : 0),
|
||||||
spending_proposals: SpendingProposal.where(author_id: @user.id).count)
|
comments: only_active_commentables.count)
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_filtered_activity
|
def load_filtered_activity
|
||||||
@@ -24,8 +23,8 @@ class UsersController < ApplicationController
|
|||||||
case params[:filter]
|
case params[:filter]
|
||||||
when "proposals" then load_proposals
|
when "proposals" then load_proposals
|
||||||
when "debates" then load_debates
|
when "debates" then load_debates
|
||||||
|
when "budget_investments" then load_budget_investments
|
||||||
when "comments" then load_comments
|
when "comments" then load_comments
|
||||||
when "spending_proposals" then load_spending_proposals if author_or_admin?
|
|
||||||
else load_available_activity
|
else load_available_activity
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -34,15 +33,15 @@ class UsersController < ApplicationController
|
|||||||
if @activity_counts[:proposals] > 0
|
if @activity_counts[:proposals] > 0
|
||||||
load_proposals
|
load_proposals
|
||||||
@current_filter = "proposals"
|
@current_filter = "proposals"
|
||||||
elsif @activity_counts[:debates] > 0
|
elsif @activity_counts[:debates] > 0
|
||||||
load_debates
|
load_debates
|
||||||
@current_filter = "debates"
|
@current_filter = "debates"
|
||||||
|
elsif @activity_counts[:budget_investments] > 0
|
||||||
|
load_budget_investments
|
||||||
|
@current_filter = "budget_investments"
|
||||||
elsif @activity_counts[:comments] > 0
|
elsif @activity_counts[:comments] > 0
|
||||||
load_comments
|
load_comments
|
||||||
@current_filter = "comments"
|
@current_filter = "comments"
|
||||||
elsif @activity_counts[:spending_proposals] > 0 && author_or_admin?
|
|
||||||
load_spending_proposals
|
|
||||||
@current_filter = "spending_proposals"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -55,11 +54,11 @@ class UsersController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def load_comments
|
def load_comments
|
||||||
@comments = Comment.not_as_admin_or_moderator.where(user_id: @user.id).includes(:commentable).order(created_at: :desc).page(params[:page])
|
@comments = only_active_commentables.includes(:commentable).order(created_at: :desc).page(params[:page])
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_spending_proposals
|
def load_budget_investments
|
||||||
@spending_proposals = SpendingProposal.where(author_id: @user.id).order(created_at: :desc).page(params[:page])
|
@budget_investments = Budget::Investment.where(author_id: @user.id).order(created_at: :desc).page(params[:page])
|
||||||
end
|
end
|
||||||
|
|
||||||
def valid_access?
|
def valid_access?
|
||||||
@@ -78,7 +77,19 @@ class UsersController < ApplicationController
|
|||||||
@authorized_current_user ||= current_user && (current_user == @user || current_user.moderator? || current_user.administrator?)
|
@authorized_current_user ||= current_user && (current_user == @user || current_user.moderator? || current_user.administrator?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorized_for_filter?(filter)
|
def all_user_comments
|
||||||
filter == "spending_proposals" ? author_or_admin? : true
|
Comment.not_as_admin_or_moderator.where(user_id: @user.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def only_active_commentables
|
||||||
|
disabled_commentables = []
|
||||||
|
disabled_commentables << "Debate" unless Setting['feature.debates']
|
||||||
|
disabled_commentables << "Budget::Investment" unless Setting['feature.budgets']
|
||||||
|
if disabled_commentables.present?
|
||||||
|
all_user_comments.where("commentable_type NOT IN (?)", disabled_commentables)
|
||||||
|
else
|
||||||
|
all_user_comments
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
79
app/controllers/valuation/budget_investments_controller.rb
Normal file
79
app/controllers/valuation/budget_investments_controller.rb
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
class Valuation::BudgetInvestmentsController < Valuation::BaseController
|
||||||
|
include FeatureFlags
|
||||||
|
feature_flag :budgets
|
||||||
|
|
||||||
|
before_action :restrict_access_to_assigned_items, only: [:show, :edit, :valuate]
|
||||||
|
before_action :load_budget
|
||||||
|
before_action :load_investment, only: [:show, :edit, :valuate]
|
||||||
|
|
||||||
|
has_filters %w{valuating valuation_finished}, only: :index
|
||||||
|
|
||||||
|
load_and_authorize_resource :investment, class: "Budget::Investment"
|
||||||
|
|
||||||
|
def index
|
||||||
|
@heading_filters = heading_filters
|
||||||
|
if current_user.valuator? && @budget.present?
|
||||||
|
@investments = @budget.investments.scoped_filter(params_for_current_valuator, @current_filter).order(cached_votes_up: :desc).page(params[:page])
|
||||||
|
else
|
||||||
|
@investments = Budget::Investment.none.page(params[:page])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def valuate
|
||||||
|
if valid_price_params? && @investment.update(valuation_params)
|
||||||
|
redirect_to valuation_budget_budget_investment_path(@budget, @investment), notice: t('valuation.budget_investments.notice.valuate')
|
||||||
|
else
|
||||||
|
render action: :edit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_budget
|
||||||
|
@budget = Budget.find(params[:budget_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_investment
|
||||||
|
@investment = @budget.investments.find params[:id]
|
||||||
|
end
|
||||||
|
|
||||||
|
def heading_filters
|
||||||
|
investments = @budget.investments.by_valuator(current_user.valuator.try(:id)).valuation_open.select(:heading_id).all.to_a
|
||||||
|
|
||||||
|
[ { name: t('valuation.budget_investments.index.headings_filter_all'),
|
||||||
|
id: nil,
|
||||||
|
pending_count: investments.size
|
||||||
|
}
|
||||||
|
] + Budget::Heading.where(id: investments.map(&:heading_id).uniq).order(name: :asc).collect do |h|
|
||||||
|
{ name: h.name,
|
||||||
|
id: h.id,
|
||||||
|
pending_count: investments.count{|x| x.heading_id == h.id}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def params_for_current_valuator
|
||||||
|
Budget::Investment.filter_params(params).merge({valuator_id: current_user.valuator.id, budget_id: @budget.id})
|
||||||
|
end
|
||||||
|
|
||||||
|
def valuation_params
|
||||||
|
params.require(:budget_investment).permit(:price, :price_first_year, :price_explanation, :feasibility, :unfeasibility_explanation, :duration, :valuation_finished, :internal_comments)
|
||||||
|
end
|
||||||
|
|
||||||
|
def restrict_access_to_assigned_items
|
||||||
|
raise ActionController::RoutingError.new('Not Found') unless current_user.administrator? || Budget::ValuatorAssignment.exists?(investment_id: params[:id], valuator_id: current_user.valuator.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid_price_params?
|
||||||
|
if /\D/.match params[:budget_investment][:price]
|
||||||
|
@investment.errors.add(:price, I18n.t('budgets.investments.wrong_price_format'))
|
||||||
|
end
|
||||||
|
|
||||||
|
if /\D/.match params[:budget_investment][:price_first_year]
|
||||||
|
@investment.errors.add(:price_first_year, I18n.t('budgets.investments.wrong_price_format'))
|
||||||
|
end
|
||||||
|
|
||||||
|
@investment.errors.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
17
app/controllers/valuation/budgets_controller.rb
Normal file
17
app/controllers/valuation/budgets_controller.rb
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
class Valuation::BudgetsController < Valuation::BaseController
|
||||||
|
include FeatureFlags
|
||||||
|
feature_flag :budgets
|
||||||
|
|
||||||
|
load_and_authorize_resource
|
||||||
|
|
||||||
|
def index
|
||||||
|
@budgets = @budgets.current.order(created_at: :desc).page(params[:page])
|
||||||
|
@investments_with_valuation_open = {}
|
||||||
|
@budgets.each do |b|
|
||||||
|
@investments_with_valuation_open[b.id] = b.investments
|
||||||
|
.by_valuator(current_user.valuator.try(:id))
|
||||||
|
.valuation_open
|
||||||
|
.count
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -42,4 +42,11 @@ module ApplicationHelper
|
|||||||
return false if authorable.blank? || user.blank?
|
return false if authorable.blank? || user.blank?
|
||||||
authorable.author_id == user.id
|
authorable.author_id == user.id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def back_link_to(destination_path)
|
||||||
|
destination = destination_path || :back
|
||||||
|
link_to destination, class: "back" do
|
||||||
|
"<span class='icon-angle-left'></span>".html_safe + t("shared.back")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
7
app/helpers/ballots_helper.rb
Normal file
7
app/helpers/ballots_helper.rb
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
module BallotsHelper
|
||||||
|
|
||||||
|
def progress_bar_width(amount_available, amount_spent)
|
||||||
|
(amount_spent/amount_available.to_f * 100).to_s + "%"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
9
app/helpers/budget_headings_helper.rb
Normal file
9
app/helpers/budget_headings_helper.rb
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
module BudgetHeadingsHelper
|
||||||
|
|
||||||
|
def budget_heading_select_options(budget)
|
||||||
|
budget.headings.order_by_group_name.map do |heading|
|
||||||
|
[heading.name_scoped_by_group, heading.id]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
41
app/helpers/budgets_helper.rb
Normal file
41
app/helpers/budgets_helper.rb
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
module BudgetsHelper
|
||||||
|
|
||||||
|
def budget_phases_select_options
|
||||||
|
Budget::PHASES.map { |ph| [ t("budgets.phase.#{ph}"), ph ] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def budget_currency_symbol_select_options
|
||||||
|
Budget::CURRENCY_SYMBOLS.map { |cs| [ cs, cs ] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def namespaced_budget_investment_path(investment, options={})
|
||||||
|
case namespace
|
||||||
|
when "management::budgets"
|
||||||
|
management_budget_investment_path(investment.budget, investment, options)
|
||||||
|
else
|
||||||
|
budget_investment_path(investment.budget, investment, options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def namespaced_budget_investment_vote_path(investment, options={})
|
||||||
|
case namespace
|
||||||
|
when "management::budgets"
|
||||||
|
vote_management_budget_investment_path(investment.budget, investment, options)
|
||||||
|
else
|
||||||
|
vote_budget_investment_path(investment.budget, investment, options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def display_budget_countdown?(budget)
|
||||||
|
budget.balloting?
|
||||||
|
end
|
||||||
|
|
||||||
|
def css_for_ballot_heading(heading)
|
||||||
|
return '' unless current_ballot.present?
|
||||||
|
current_ballot.has_lines_in_heading?(heading) ? 'active' : ''
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_ballot
|
||||||
|
Budget::Ballot.where(user: current_user, budget: @budget).first
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -20,6 +20,14 @@ module CommentsHelper
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def commentable_path(comment)
|
||||||
|
if comment.commentable_type == "Budget::Investment"
|
||||||
|
budget_investment_path(comment.commentable.budget_id, comment.commentable)
|
||||||
|
else
|
||||||
|
comment.commentable
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def user_level_class(comment)
|
def user_level_class(comment)
|
||||||
if comment.as_administrator?
|
if comment.as_administrator?
|
||||||
"is-admin"
|
"is-admin"
|
||||||
|
|||||||
@@ -8,4 +8,9 @@ module GeozonesHelper
|
|||||||
Geozone.all.order(name: :asc).collect { |g| [ g.name, g.id ] }
|
Geozone.all.order(name: :asc).collect { |g| [ g.name, g.id ] }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def geozone_name_from_id(g_id)
|
||||||
|
@all_geozones ||= Geozone.all.collect{ |g| [ g.id, g.name ] }.to_h
|
||||||
|
@all_geozones[g_id] || t("geozones.none")
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ module MailerHelper
|
|||||||
def commentable_url(commentable)
|
def commentable_url(commentable)
|
||||||
return debate_url(commentable) if commentable.is_a?(Debate)
|
return debate_url(commentable) if commentable.is_a?(Debate)
|
||||||
return proposal_url(commentable) if commentable.is_a?(Proposal)
|
return proposal_url(commentable) if commentable.is_a?(Proposal)
|
||||||
|
return budget_investment_url(commentable.budget_id, commentable) if commentable.is_a?(Budget::Investment)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
module OrdersHelper
|
|
||||||
|
|
||||||
def valid_orders
|
|
||||||
@valid_orders.reject { |order| order =='relevance' && params[:search].blank? }
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -6,6 +6,8 @@ module TagsHelper
|
|||||||
debates_path(search: tag_name)
|
debates_path(search: tag_name)
|
||||||
when 'proposal'
|
when 'proposal'
|
||||||
proposals_path(search: tag_name)
|
proposals_path(search: tag_name)
|
||||||
|
when 'budget/investment'
|
||||||
|
budget_investments_path(@budget, search: tag_name)
|
||||||
else
|
else
|
||||||
'#'
|
'#'
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ module UsersHelper
|
|||||||
t("users.show.deleted_proposal")
|
t("users.show.deleted_proposal")
|
||||||
when "Debate"
|
when "Debate"
|
||||||
t("users.show.deleted_debate")
|
t("users.show.deleted_debate")
|
||||||
|
when "Budget::Investment"
|
||||||
|
t("users.show.deleted_budget_investment")
|
||||||
else
|
else
|
||||||
t("users.show.deleted")
|
t("users.show.deleted")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ module ValuationHelper
|
|||||||
def assigned_valuators_info(valuators)
|
def assigned_valuators_info(valuators)
|
||||||
case valuators.size
|
case valuators.size
|
||||||
when 0
|
when 0
|
||||||
t("valuation.spending_proposals.index.no_valuators_assigned")
|
t("valuation.budget_investments.index.no_valuators_assigned")
|
||||||
when 1
|
when 1
|
||||||
"<span title=\"#{t('valuation.spending_proposals.index.valuators_assigned', count: 1)}\">".html_safe +
|
"<span title=\"#{t('valuation.budget_investments.index.valuators_assigned', count: 1)}\">".html_safe +
|
||||||
valuators.first.name +
|
valuators.first.name +
|
||||||
"</span>".html_safe
|
"</span>".html_safe
|
||||||
else
|
else
|
||||||
"<span title=\"".html_safe + valuators.map(&:name).join(', ') + "\">".html_safe +
|
"<span title=\"".html_safe + valuators.map(&:name).join(', ') + "\">".html_safe +
|
||||||
t('valuation.spending_proposals.index.valuators_assigned', count: valuators.size) +
|
t('valuation.budget_investments.index.valuators_assigned', count: valuators.size) +
|
||||||
"</span>".html_safe
|
"</span>".html_safe
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ module Abilities
|
|||||||
|
|
||||||
def initialize(user)
|
def initialize(user)
|
||||||
self.merge Abilities::Moderation.new(user)
|
self.merge Abilities::Moderation.new(user)
|
||||||
self.merge Abilities::Valuator.new(user)
|
|
||||||
|
|
||||||
can :restore, Comment
|
can :restore, Comment
|
||||||
cannot :restore, Comment, hidden_at: nil
|
cannot :restore, Comment, hidden_at: nil
|
||||||
@@ -33,7 +32,7 @@ module Abilities
|
|||||||
can :mark_featured, Debate
|
can :mark_featured, Debate
|
||||||
can :unmark_featured, Debate
|
can :unmark_featured, Debate
|
||||||
|
|
||||||
can :comment_as_administrator, [Debate, Comment, Proposal, Legislation::Question, Legislation::Annotation]
|
can :comment_as_administrator, [Debate, Comment, Proposal, Budget::Investment, Legislation::Question, Legislation::Annotation]
|
||||||
|
|
||||||
can [:search, :create, :index, :destroy], ::Moderator
|
can [:search, :create, :index, :destroy], ::Moderator
|
||||||
can [:search, :create, :index, :summary], ::Valuator
|
can [:search, :create, :index, :summary], ::Valuator
|
||||||
@@ -41,7 +40,15 @@ module Abilities
|
|||||||
|
|
||||||
can :manage, Annotation
|
can :manage, Annotation
|
||||||
|
|
||||||
can [:read, :update, :destroy, :summary], SpendingProposal
|
can [:read, :update, :valuate, :destroy, :summary], SpendingProposal
|
||||||
|
|
||||||
|
can [:index, :read, :new, :create, :update, :destroy], Budget
|
||||||
|
can [:read, :create, :update, :destroy], Budget::Group
|
||||||
|
can [:read, :create, :update, :destroy], Budget::Heading
|
||||||
|
can [:hide, :update, :toggle_selection], Budget::Investment
|
||||||
|
can :valuate, Budget::Investment
|
||||||
|
can :create, Budget::ValuatorAssignment
|
||||||
|
|
||||||
can [:search, :edit, :update, :create, :index, :destroy], Banner
|
can [:search, :edit, :update, :create, :index, :destroy], Banner
|
||||||
|
|
||||||
can [:index, :create, :edit, :update, :destroy], Geozone
|
can [:index, :create, :edit, :update, :destroy], Geozone
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ module Abilities
|
|||||||
end
|
end
|
||||||
can [:retire_form, :retire], Proposal, author_id: user.id
|
can [:retire_form, :retire], Proposal, author_id: user.id
|
||||||
|
|
||||||
can :read, SpendingProposal
|
|
||||||
|
|
||||||
can :create, Comment
|
can :create, Comment
|
||||||
can :create, Debate
|
can :create, Debate
|
||||||
can :create, Proposal
|
can :create, Proposal
|
||||||
@@ -46,6 +44,12 @@ module Abilities
|
|||||||
can :vote_featured, Proposal
|
can :vote_featured, Proposal
|
||||||
can :vote, SpendingProposal
|
can :vote, SpendingProposal
|
||||||
can :create, SpendingProposal
|
can :create, SpendingProposal
|
||||||
|
|
||||||
|
can :create, Budget::Investment, budget: { phase: "accepting" }
|
||||||
|
can :vote, Budget::Investment, budget: { phase: "selecting" }
|
||||||
|
can [:show, :create], Budget::Ballot, budget: { phase: "balloting" }
|
||||||
|
can [:create, :destroy], Budget::Ballot::Line, budget: { phase: "balloting" }
|
||||||
|
|
||||||
can :create, DirectMessage
|
can :create, DirectMessage
|
||||||
can :show, DirectMessage, sender_id: user.id
|
can :show, DirectMessage, sender_id: user.id
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -6,10 +6,15 @@ module Abilities
|
|||||||
can [:read, :map], Debate
|
can [:read, :map], Debate
|
||||||
can [:read, :map, :summary], Proposal
|
can [:read, :map, :summary], Proposal
|
||||||
can :read, Comment
|
can :read, Comment
|
||||||
|
can [:read, :welcome], Budget
|
||||||
|
can :read, Budget::Investment
|
||||||
can :read, SpendingProposal
|
can :read, SpendingProposal
|
||||||
can :read, LegacyLegislation
|
can :read, LegacyLegislation
|
||||||
can :read, User
|
can :read, User
|
||||||
can [:search, :read], Annotation
|
can [:search, :read], Annotation
|
||||||
|
can [:read], Budget
|
||||||
|
can [:read], Budget::Group
|
||||||
|
can [:read, :print], Budget::Investment
|
||||||
can :new, DirectMessage
|
can :new, DirectMessage
|
||||||
can [:read, :draft_publication, :allegations, :final_version_publication], Legislation::Process
|
can [:read, :draft_publication, :allegations, :final_version_publication], Legislation::Process
|
||||||
can [:read, :changes, :go_to_version], Legislation::DraftVersion
|
can [:read, :changes, :go_to_version], Legislation::DraftVersion
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ module Abilities
|
|||||||
def initialize(user)
|
def initialize(user)
|
||||||
self.merge Abilities::Moderation.new(user)
|
self.merge Abilities::Moderation.new(user)
|
||||||
|
|
||||||
can :comment_as_moderator, [Debate, Comment, Proposal, Legislation::Question, Legislation::Annotation]
|
can :comment_as_moderator, [Debate, Comment, Proposal, Budget::Investment, Legislation::Question, Legislation::Annotation]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ module Abilities
|
|||||||
include CanCan::Ability
|
include CanCan::Ability
|
||||||
|
|
||||||
def initialize(user)
|
def initialize(user)
|
||||||
|
valuator = user.valuator
|
||||||
can [:read, :update, :valuate], SpendingProposal
|
can [:read, :update, :valuate], SpendingProposal
|
||||||
|
can [:read, :update, :valuate], Budget::Investment, id: valuator.investment_ids
|
||||||
|
cannot [:update, :valuate], Budget::Investment, budget: { phase: 'finished' }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
118
app/models/budget.rb
Normal file
118
app/models/budget.rb
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
class Budget < ActiveRecord::Base
|
||||||
|
|
||||||
|
include Measurable
|
||||||
|
|
||||||
|
PHASES = %w(accepting reviewing selecting valuating balloting reviewing_ballots finished).freeze
|
||||||
|
CURRENCY_SYMBOLS = %w(€ $ £ ¥).freeze
|
||||||
|
|
||||||
|
validates :name, presence: true
|
||||||
|
validates :phase, inclusion: { in: PHASES }
|
||||||
|
validates :currency_symbol, presence: true
|
||||||
|
|
||||||
|
has_many :investments, dependent: :destroy
|
||||||
|
has_many :ballots, dependent: :destroy
|
||||||
|
has_many :groups, dependent: :destroy
|
||||||
|
has_many :headings, through: :groups
|
||||||
|
|
||||||
|
before_validation :sanitize_descriptions
|
||||||
|
|
||||||
|
scope :on_hold, -> { where(phase: %w(reviewing valuating reviewing_ballots")) }
|
||||||
|
scope :accepting, -> { where(phase: "accepting") }
|
||||||
|
scope :reviewing, -> { where(phase: "reviewing") }
|
||||||
|
scope :selecting, -> { where(phase: "selecting") }
|
||||||
|
scope :valuating, -> { where(phase: "valuating") }
|
||||||
|
scope :balloting, -> { where(phase: "balloting") }
|
||||||
|
scope :reviewing_ballots, -> { where(phase: "reviewing_ballots") }
|
||||||
|
scope :finished, -> { where(phase: "finished") }
|
||||||
|
|
||||||
|
scope :current, -> { where.not(phase: "finished") }
|
||||||
|
|
||||||
|
def description
|
||||||
|
self.send("description_#{self.phase}").try(:html_safe)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.description_max_length
|
||||||
|
2000
|
||||||
|
end
|
||||||
|
|
||||||
|
def accepting?
|
||||||
|
phase == "accepting"
|
||||||
|
end
|
||||||
|
|
||||||
|
def reviewing?
|
||||||
|
phase == "reviewing"
|
||||||
|
end
|
||||||
|
|
||||||
|
def selecting?
|
||||||
|
phase == "selecting"
|
||||||
|
end
|
||||||
|
|
||||||
|
def valuating?
|
||||||
|
phase == "valuating"
|
||||||
|
end
|
||||||
|
|
||||||
|
def balloting?
|
||||||
|
phase == "balloting"
|
||||||
|
end
|
||||||
|
|
||||||
|
def reviewing_ballots?
|
||||||
|
phase == "reviewing_ballots"
|
||||||
|
end
|
||||||
|
|
||||||
|
def finished?
|
||||||
|
phase == "finished"
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_hold?
|
||||||
|
reviewing? || valuating? || reviewing_ballots?
|
||||||
|
end
|
||||||
|
|
||||||
|
def current?
|
||||||
|
!finished?
|
||||||
|
end
|
||||||
|
|
||||||
|
def heading_price(heading)
|
||||||
|
heading_ids.include?(heading.id) ? heading.price : -1
|
||||||
|
end
|
||||||
|
|
||||||
|
def translated_phase
|
||||||
|
I18n.t "budgets.phase.#{phase}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def formatted_amount(amount)
|
||||||
|
ActionController::Base.helpers.number_to_currency(amount,
|
||||||
|
precision: 0,
|
||||||
|
locale: I18n.default_locale,
|
||||||
|
unit: currency_symbol)
|
||||||
|
end
|
||||||
|
|
||||||
|
def formatted_heading_price(heading)
|
||||||
|
formatted_amount(heading_price(heading))
|
||||||
|
end
|
||||||
|
|
||||||
|
def formatted_heading_amount_spent(heading)
|
||||||
|
formatted_amount(amount_spent(heading))
|
||||||
|
end
|
||||||
|
|
||||||
|
def investments_orders
|
||||||
|
case phase
|
||||||
|
when 'accepting', 'reviewing'
|
||||||
|
%w{random}
|
||||||
|
when 'balloting', 'reviewing_ballots'
|
||||||
|
%w{random price}
|
||||||
|
else
|
||||||
|
%w{random confidence_score}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def sanitize_descriptions
|
||||||
|
s = WYSIWYGSanitizer.new
|
||||||
|
PHASES.each do |phase|
|
||||||
|
sanitized = s.sanitize(self.send("description_#{phase}"))
|
||||||
|
self.send("description_#{phase}=", sanitized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
73
app/models/budget/ballot.rb
Normal file
73
app/models/budget/ballot.rb
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
class Budget
|
||||||
|
class Ballot < ActiveRecord::Base
|
||||||
|
belongs_to :user
|
||||||
|
belongs_to :budget
|
||||||
|
|
||||||
|
has_many :lines, dependent: :destroy
|
||||||
|
has_many :investments, through: :lines
|
||||||
|
has_many :groups, -> { uniq }, through: :lines
|
||||||
|
has_many :headings, -> { uniq }, through: :groups
|
||||||
|
|
||||||
|
def add_investment(investment)
|
||||||
|
lines.create!(investment: investment)
|
||||||
|
end
|
||||||
|
|
||||||
|
def total_amount_spent
|
||||||
|
investments.sum(:price).to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
def amount_spent(heading)
|
||||||
|
investments.by_heading(heading.id).sum(:price).to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
def formatted_amount_spent(heading)
|
||||||
|
budget.formatted_amount(amount_spent(heading))
|
||||||
|
end
|
||||||
|
|
||||||
|
def amount_available(heading)
|
||||||
|
budget.heading_price(heading) - amount_spent(heading)
|
||||||
|
end
|
||||||
|
|
||||||
|
def formatted_amount_available(heading)
|
||||||
|
budget.formatted_amount(amount_available(heading))
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_lines_in_group?(group)
|
||||||
|
self.groups.include?(group)
|
||||||
|
end
|
||||||
|
|
||||||
|
def wrong_budget?(heading)
|
||||||
|
heading.budget_id != budget_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def different_heading_assigned?(heading)
|
||||||
|
other_heading_ids = heading.group.heading_ids - [heading.id]
|
||||||
|
lines.where(heading_id: other_heading_ids).exists?
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid_heading?(heading)
|
||||||
|
!wrong_budget?(heading) && !different_heading_assigned?(heading)
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_lines_with_no_heading?
|
||||||
|
investments.no_heading.count > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_lines_with_heading?
|
||||||
|
self.heading_id.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_lines_in_heading?(heading)
|
||||||
|
investments.by_heading(heading.id).any?
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_investment?(investment)
|
||||||
|
self.investment_ids.include?(investment.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def heading_for_group(group)
|
||||||
|
self.headings.where(group: group).first
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
39
app/models/budget/ballot/line.rb
Normal file
39
app/models/budget/ballot/line.rb
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
class Budget
|
||||||
|
class Ballot
|
||||||
|
class Line < ActiveRecord::Base
|
||||||
|
belongs_to :ballot
|
||||||
|
belongs_to :investment
|
||||||
|
belongs_to :heading
|
||||||
|
belongs_to :group
|
||||||
|
belongs_to :budget
|
||||||
|
|
||||||
|
validates :ballot_id, :investment_id, :heading_id, :group_id, :budget_id, presence: true
|
||||||
|
|
||||||
|
validate :check_selected
|
||||||
|
validate :check_sufficient_funds
|
||||||
|
validate :check_valid_heading
|
||||||
|
|
||||||
|
before_validation :set_denormalized_ids
|
||||||
|
|
||||||
|
def check_sufficient_funds
|
||||||
|
errors.add(:money, "insufficient funds") if ballot.amount_available(investment.heading) < investment.price.to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_valid_heading
|
||||||
|
errors.add(:heading, "This heading's budget is invalid, or a heading on the same group was already selected") unless ballot.valid_heading?(self.heading)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_selected
|
||||||
|
errors.add(:investment, "unselected investment") unless investment.selected?
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_denormalized_ids
|
||||||
|
self.heading_id ||= self.investment.try(:heading_id)
|
||||||
|
self.group_id ||= self.investment.try(:group_id)
|
||||||
|
self.budget_id ||= self.investment.try(:budget_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
10
app/models/budget/group.rb
Normal file
10
app/models/budget/group.rb
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
class Budget
|
||||||
|
class Group < ActiveRecord::Base
|
||||||
|
belongs_to :budget
|
||||||
|
|
||||||
|
has_many :headings, dependent: :destroy
|
||||||
|
|
||||||
|
validates :budget_id, presence: true
|
||||||
|
validates :name, presence: true
|
||||||
|
end
|
||||||
|
end
|
||||||
20
app/models/budget/heading.rb
Normal file
20
app/models/budget/heading.rb
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
class Budget
|
||||||
|
class Heading < ActiveRecord::Base
|
||||||
|
belongs_to :group
|
||||||
|
|
||||||
|
has_many :investments
|
||||||
|
|
||||||
|
validates :group_id, presence: true
|
||||||
|
validates :name, presence: true
|
||||||
|
validates :price, presence: true
|
||||||
|
|
||||||
|
delegate :budget, :budget_id, to: :group, allow_nil: true
|
||||||
|
|
||||||
|
scope :order_by_group_name, -> { includes(:group).order('budget_groups.name', 'budget_headings.name') }
|
||||||
|
|
||||||
|
def name_scoped_by_group
|
||||||
|
"#{group.name}: #{name}"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
232
app/models/budget/investment.rb
Normal file
232
app/models/budget/investment.rb
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
class Budget
|
||||||
|
class Investment < ActiveRecord::Base
|
||||||
|
|
||||||
|
include Measurable
|
||||||
|
include Sanitizable
|
||||||
|
include Taggable
|
||||||
|
include Searchable
|
||||||
|
|
||||||
|
acts_as_votable
|
||||||
|
acts_as_paranoid column: :hidden_at
|
||||||
|
include ActsAsParanoidAliases
|
||||||
|
|
||||||
|
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
|
||||||
|
belongs_to :heading
|
||||||
|
belongs_to :group
|
||||||
|
belongs_to :budget
|
||||||
|
belongs_to :administrator
|
||||||
|
|
||||||
|
has_many :valuator_assignments, dependent: :destroy
|
||||||
|
has_many :valuators, through: :valuator_assignments
|
||||||
|
has_many :comments, as: :commentable
|
||||||
|
|
||||||
|
validates :title, presence: true
|
||||||
|
validates :author, presence: true
|
||||||
|
validates :description, presence: true
|
||||||
|
validates :heading_id, presence: true
|
||||||
|
validates_presence_of :unfeasibility_explanation, if: :unfeasibility_explanation_required?
|
||||||
|
|
||||||
|
validates :title, length: { in: 4..Budget::Investment.title_max_length }
|
||||||
|
validates :description, length: { maximum: Budget::Investment.description_max_length }
|
||||||
|
validates :terms_of_service, acceptance: { allow_nil: false }, on: :create
|
||||||
|
|
||||||
|
scope :sort_by_confidence_score, -> { reorder(confidence_score: :desc, id: :desc) }
|
||||||
|
scope :sort_by_price, -> { reorder(price: :desc, confidence_score: :desc, id: :desc) }
|
||||||
|
scope :sort_by_random, -> { reorder("RANDOM()") }
|
||||||
|
|
||||||
|
scope :valuation_open, -> { where(valuation_finished: false) }
|
||||||
|
scope :without_admin, -> { valuation_open.where(administrator_id: nil) }
|
||||||
|
scope :managed, -> { valuation_open.where(valuator_assignments_count: 0).where("administrator_id IS NOT ?", nil) }
|
||||||
|
scope :valuating, -> { valuation_open.where("valuator_assignments_count > 0 AND valuation_finished = ?", false) }
|
||||||
|
scope :valuation_finished, -> { where(valuation_finished: true) }
|
||||||
|
scope :valuation_finished_feasible, -> { where(valuation_finished: true, feasibility: "feasible") }
|
||||||
|
scope :feasible, -> { where(feasibility: "feasible") }
|
||||||
|
scope :unfeasible, -> { where(feasibility: "unfeasible") }
|
||||||
|
scope :not_unfeasible, -> { where.not(feasibility: "unfeasible") }
|
||||||
|
scope :undecided, -> { where(feasibility: "undecided") }
|
||||||
|
scope :with_supports, -> { where('cached_votes_up > 0') }
|
||||||
|
scope :selected, -> { where(selected: true) }
|
||||||
|
scope :last_week, -> { where("created_at >= ?", 7.days.ago)}
|
||||||
|
|
||||||
|
scope :by_group, -> (group_id) { where(group_id: group_id) }
|
||||||
|
scope :by_heading, -> (heading_id) { where(heading_id: heading_id) }
|
||||||
|
scope :by_admin, -> (admin_id) { where(administrator_id: admin_id) }
|
||||||
|
scope :by_tag, -> (tag_name) { tagged_with(tag_name) }
|
||||||
|
scope :by_valuator, -> (valuator_id) { where("budget_valuator_assignments.valuator_id = ?", valuator_id).joins(:valuator_assignments) }
|
||||||
|
|
||||||
|
scope :for_render, -> { includes(:heading) }
|
||||||
|
|
||||||
|
before_save :calculate_confidence_score
|
||||||
|
before_validation :set_responsible_name
|
||||||
|
before_validation :set_denormalized_ids
|
||||||
|
|
||||||
|
def self.filter_params(params)
|
||||||
|
params.select{|x,_| %w{heading_id group_id administrator_id tag_name valuator_id}.include? x.to_s }
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.scoped_filter(params, current_filter)
|
||||||
|
results = Investment.where(budget_id: params[:budget_id])
|
||||||
|
results = results.where(group_id: params[:group_id]) if params[:group_id].present?
|
||||||
|
results = results.by_heading(params[:heading_id]) if params[:heading_id].present?
|
||||||
|
results = results.by_admin(params[:administrator_id]) if params[:administrator_id].present?
|
||||||
|
results = results.by_tag(params[:tag_name]) if params[:tag_name].present?
|
||||||
|
results = results.by_valuator(params[:valuator_id]) if params[:valuator_id].present?
|
||||||
|
results = results.send(current_filter) if current_filter.present?
|
||||||
|
results.includes(:heading, :group, :budget, administrator: :user, valuators: :user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.limit_results(results, budget, max_per_heading, max_for_no_heading)
|
||||||
|
return results if max_per_heading <= 0 && max_for_no_heading <= 0
|
||||||
|
|
||||||
|
ids = []
|
||||||
|
if max_per_heading > 0
|
||||||
|
budget.headings.pluck(:id).each do |hid|
|
||||||
|
ids += Investment.where(heading_id: hid).order(confidence_score: :desc).limit(max_per_heading).pluck(:id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if max_for_no_heading > 0
|
||||||
|
ids += Investment.no_heading.order(confidence_score: :desc).limit(max_for_no_heading).pluck(:id)
|
||||||
|
end
|
||||||
|
|
||||||
|
conditions = ["investments.id IN (?)"]
|
||||||
|
values = [ids]
|
||||||
|
|
||||||
|
if max_per_heading == 0
|
||||||
|
conditions << "investments.heading_id IS NOT ?"
|
||||||
|
values << nil
|
||||||
|
elsif max_for_no_heading == 0
|
||||||
|
conditions << "investments.heading_id IS ?"
|
||||||
|
values << nil
|
||||||
|
end
|
||||||
|
|
||||||
|
results.where(conditions.join(' OR '), *values)
|
||||||
|
end
|
||||||
|
|
||||||
|
def searchable_values
|
||||||
|
{ title => 'A',
|
||||||
|
author.username => 'B',
|
||||||
|
heading.try(:name) => 'B',
|
||||||
|
tag_list.join(' ') => 'B',
|
||||||
|
description => 'C'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.search(terms)
|
||||||
|
self.pg_search(terms)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.by_heading(heading)
|
||||||
|
where(heading_id: heading == 'all' ? nil : heading.presence)
|
||||||
|
end
|
||||||
|
|
||||||
|
def undecided?
|
||||||
|
feasibility == "undecided"
|
||||||
|
end
|
||||||
|
|
||||||
|
def feasible?
|
||||||
|
feasibility == "feasible"
|
||||||
|
end
|
||||||
|
|
||||||
|
def unfeasible?
|
||||||
|
feasibility == "unfeasible"
|
||||||
|
end
|
||||||
|
|
||||||
|
def unfeasibility_explanation_required?
|
||||||
|
unfeasible? && valuation_finished?
|
||||||
|
end
|
||||||
|
|
||||||
|
def total_votes
|
||||||
|
cached_votes_up + physical_votes
|
||||||
|
end
|
||||||
|
|
||||||
|
def code
|
||||||
|
"B#{budget.id}I#{id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def reason_for_not_being_selectable_by(user)
|
||||||
|
return permission_problem(user) if permission_problem?(user)
|
||||||
|
|
||||||
|
return :no_selecting_allowed unless budget.selecting?
|
||||||
|
end
|
||||||
|
|
||||||
|
def reason_for_not_being_ballotable_by(user, ballot)
|
||||||
|
return permission_problem(user) if permission_problem?(user)
|
||||||
|
return :not_selected unless selected?
|
||||||
|
return :no_ballots_allowed unless budget.balloting?
|
||||||
|
return :different_heading_assigned unless ballot.valid_heading?(heading)
|
||||||
|
return :not_enough_money if ballot.present? && !enough_money?(ballot)
|
||||||
|
end
|
||||||
|
|
||||||
|
def permission_problem(user)
|
||||||
|
return :not_logged_in unless user
|
||||||
|
return :organization if user.organization?
|
||||||
|
return :not_verified unless user.can?(:vote, Budget::Investment)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def permission_problem?(user)
|
||||||
|
permission_problem(user).present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def selectable_by?(user)
|
||||||
|
reason_for_not_being_selectable_by(user).blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
def ballotable_by?(user)
|
||||||
|
reason_for_not_being_ballotable_by(user).blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
def enough_money?(ballot)
|
||||||
|
available_money = ballot.amount_available(self.heading)
|
||||||
|
price.to_i <= available_money
|
||||||
|
end
|
||||||
|
|
||||||
|
def register_selection(user)
|
||||||
|
vote_by(voter: user, vote: 'yes') if selectable_by?(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def calculate_confidence_score
|
||||||
|
self.confidence_score = ScoreCalculator.confidence_score(total_votes, total_votes)
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_responsible_name
|
||||||
|
self.responsible_name = author.try(:document_number) if author.try(:document_number).present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def should_show_aside?
|
||||||
|
(budget.selecting? && !unfeasible?) || (budget.balloting? && feasible?) || budget.on_hold?
|
||||||
|
end
|
||||||
|
|
||||||
|
def should_show_votes?
|
||||||
|
budget.selecting? || budget.on_hold?
|
||||||
|
end
|
||||||
|
|
||||||
|
def should_show_ballots?
|
||||||
|
budget.balloting?
|
||||||
|
end
|
||||||
|
|
||||||
|
def formatted_price
|
||||||
|
budget.formatted_amount(price)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.apply_filters_and_search(budget, params)
|
||||||
|
investments = all
|
||||||
|
if budget.balloting?
|
||||||
|
investments = investments.selected
|
||||||
|
else
|
||||||
|
investments = params[:unfeasible].present? ? investments.unfeasible : investments.not_unfeasible
|
||||||
|
end
|
||||||
|
investments = investments.by_heading(params[:heading_id]) if params[:heading_id].present?
|
||||||
|
investments = investments.search(params[:search]) if params[:search].present?
|
||||||
|
investments
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_denormalized_ids
|
||||||
|
self.group_id ||= self.heading.try(:group_id)
|
||||||
|
self.budget_id ||= self.heading.try(:group).try(:budget_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
6
app/models/budget/valuator_assignment.rb
Normal file
6
app/models/budget/valuator_assignment.rb
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
class Budget
|
||||||
|
class ValuatorAssignment < ActiveRecord::Base
|
||||||
|
belongs_to :valuator, counter_cache: :budget_investments_count
|
||||||
|
belongs_to :investment, counter_cache: true
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -10,7 +10,7 @@ class Comment < ActiveRecord::Base
|
|||||||
|
|
||||||
validates :body, presence: true
|
validates :body, presence: true
|
||||||
validates :user, presence: true
|
validates :user, presence: true
|
||||||
validates_inclusion_of :commentable_type, in: ["Debate", "Proposal", "Legislation::Question", "Legislation::Annotation"]
|
validates_inclusion_of :commentable_type, in: ["Debate", "Proposal", "Budget::Investment", "Legislation::Question", "Legislation::Annotation"]
|
||||||
|
|
||||||
validate :validate_body_length
|
validate :validate_body_length
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ module Sanitizable
|
|||||||
before_validation :sanitize_tag_list
|
before_validation :sanitize_tag_list
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def description
|
||||||
|
super.try :html_safe
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def sanitize_description
|
def sanitize_description
|
||||||
|
|||||||
@@ -59,10 +59,6 @@ class Debate < ActiveRecord::Base
|
|||||||
"#{id}-#{title}".parameterize
|
"#{id}-#{title}".parameterize
|
||||||
end
|
end
|
||||||
|
|
||||||
def description
|
|
||||||
super.try :html_safe
|
|
||||||
end
|
|
||||||
|
|
||||||
def likes
|
def likes
|
||||||
cached_votes_up
|
cached_votes_up
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -94,10 +94,6 @@ class Proposal < ActiveRecord::Base
|
|||||||
summary
|
summary
|
||||||
end
|
end
|
||||||
|
|
||||||
def description
|
|
||||||
super.try :html_safe
|
|
||||||
end
|
|
||||||
|
|
||||||
def total_votes
|
def total_votes
|
||||||
cached_votes_up
|
cached_votes_up
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class TagCloud
|
|||||||
end
|
end
|
||||||
|
|
||||||
def table_name
|
def table_name
|
||||||
resource_model.to_s.downcase.pluralize
|
resource_model.to_s.downcase.pluralize.gsub("::", "/")
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -19,6 +19,7 @@ class User < ActiveRecord::Base
|
|||||||
has_many :identities, dependent: :destroy
|
has_many :identities, dependent: :destroy
|
||||||
has_many :debates, -> { with_hidden }, foreign_key: :author_id
|
has_many :debates, -> { with_hidden }, foreign_key: :author_id
|
||||||
has_many :proposals, -> { with_hidden }, foreign_key: :author_id
|
has_many :proposals, -> { with_hidden }, foreign_key: :author_id
|
||||||
|
has_many :budget_investments, -> { with_hidden }, foreign_key: :author_id, class_name: 'Budget::Investment'
|
||||||
has_many :comments, -> { with_hidden }
|
has_many :comments, -> { with_hidden }
|
||||||
has_many :spending_proposals, foreign_key: :author_id
|
has_many :spending_proposals, foreign_key: :author_id
|
||||||
has_many :failed_census_calls
|
has_many :failed_census_calls
|
||||||
@@ -93,6 +94,11 @@ class User < ActiveRecord::Base
|
|||||||
voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value }
|
voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def budget_investment_votes(budget_investments)
|
||||||
|
voted = votes.for_budget_investments(budget_investments)
|
||||||
|
voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value }
|
||||||
|
end
|
||||||
|
|
||||||
def comment_flags(comments)
|
def comment_flags(comments)
|
||||||
comment_flags = flags.for_comments(comments)
|
comment_flags = flags.for_comments(comments)
|
||||||
comment_flags.each_with_object({}){ |f, h| h[f.flaggable_id] = true }
|
comment_flags.each_with_object({}){ |f, h| h[f.flaggable_id] = true }
|
||||||
@@ -191,6 +197,10 @@ class User < ActiveRecord::Base
|
|||||||
@@username_max_length ||= self.columns.find { |c| c.name == 'username' }.limit || 60
|
@@username_max_length ||= self.columns.find { |c| c.name == 'username' }.limit || 60
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.minimum_required_age
|
||||||
|
(Setting['min_age_to_participate'] || 16).to_i
|
||||||
|
end
|
||||||
|
|
||||||
def show_welcome_screen?
|
def show_welcome_screen?
|
||||||
sign_in_count == 1 && unverified? && !organization && !administrator?
|
sign_in_count == 1 && unverified? && !organization && !administrator?
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ class Valuator < ActiveRecord::Base
|
|||||||
|
|
||||||
has_many :valuation_assignments, dependent: :destroy
|
has_many :valuation_assignments, dependent: :destroy
|
||||||
has_many :spending_proposals, through: :valuation_assignments
|
has_many :spending_proposals, through: :valuation_assignments
|
||||||
|
has_many :valuator_assignments, dependent: :destroy, class_name: 'Budget::ValuatorAssignment'
|
||||||
|
has_many :investments, through: :valuator_assignments, class_name: 'Budget::Investment'
|
||||||
|
|
||||||
validates :user_id, presence: true, uniqueness: true
|
validates :user_id, presence: true, uniqueness: true
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class Verification::Management::Document
|
|||||||
end
|
end
|
||||||
|
|
||||||
def valid_age?(response)
|
def valid_age?(response)
|
||||||
if under_sixteen?(response)
|
if under_age?(response)
|
||||||
errors.add(:age, true)
|
errors.add(:age, true)
|
||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
@@ -31,8 +31,8 @@ class Verification::Management::Document
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def under_sixteen?(response)
|
def under_age?(response)
|
||||||
16.years.ago.beginning_of_day < response.date_of_birth.beginning_of_day
|
User.minimum_required_age.years.ago.beginning_of_day < response.date_of_birth.beginning_of_day
|
||||||
end
|
end
|
||||||
|
|
||||||
def verified?
|
def verified?
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class Verification::Residence
|
|||||||
|
|
||||||
def allowed_age
|
def allowed_age
|
||||||
return if errors[:date_of_birth].any?
|
return if errors[:date_of_birth].any?
|
||||||
errors.add(:date_of_birth, I18n.t('verification.residence.new.error_not_allowed_age')) unless self.date_of_birth <= 16.years.ago
|
errors.add(:date_of_birth, I18n.t('verification.residence.new.error_not_allowed_age')) unless self.date_of_birth <= User.minimum_required_age.years.ago
|
||||||
end
|
end
|
||||||
|
|
||||||
def document_number_uniqueness
|
def document_number_uniqueness
|
||||||
|
|||||||
@@ -35,6 +35,14 @@
|
|||||||
</li>
|
</li>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
<% if feature?(:budgets) %>
|
||||||
|
<li <%= "class=active" if controller_name == "budgets" %>>
|
||||||
|
<%= link_to admin_budgets_path do %>
|
||||||
|
<span class="icon-budget"></span><%= t("admin.menu.budgets") %>
|
||||||
|
<% end %>
|
||||||
|
</li>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<% if feature?(:signature_sheets) %>
|
<% if feature?(:signature_sheets) %>
|
||||||
<li <%= "class=active" if controller_name == "signature_sheets" %>>
|
<li <%= "class=active" if controller_name == "signature_sheets" %>>
|
||||||
<%= link_to admin_signature_sheets_path do %>
|
<%= link_to admin_signature_sheets_path do %>
|
||||||
|
|||||||
2
app/views/admin/budget_groups/create.js.erb
Normal file
2
app/views/admin/budget_groups/create.js.erb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
$("#<%= dom_id(@budget) %>_groups").html('<%= j render("admin/budgets/groups", groups: @groups) %>');
|
||||||
|
App.Forms.toggleLink();
|
||||||
2
app/views/admin/budget_headings/create.js.erb
Normal file
2
app/views/admin/budget_headings/create.js.erb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
$("#<%= dom_id(@budget_group) %>").html('<%= j render("admin/budgets/group", group: @budget_group, headings: @headings) %>');
|
||||||
|
App.Forms.toggleLink();
|
||||||
77
app/views/admin/budget_investments/_investments.html.erb
Normal file
77
app/views/admin/budget_investments/_investments.html.erb
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
<h3><%= page_entries_info @investments %></h3>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><%= t("admin.budget_investments.index.table_id") %></th>
|
||||||
|
<th><%= t("admin.budget_investments.index.table_title") %></th>
|
||||||
|
<th><%= t("admin.budget_investments.index.table_admin") %></th>
|
||||||
|
<th><%= t("admin.budget_investments.index.table_valuator") %></th>
|
||||||
|
<th><%= t("admin.budget_investments.index.table_geozone") %></th>
|
||||||
|
<th><%= t("admin.budget_investments.index.table_feasibility") %></th>
|
||||||
|
<th class="text-center"><%= t("admin.budget_investments.index.table_valuation_finished") %></th>
|
||||||
|
<th class="text-center"><%= t("admin.budget_investments.index.table_selection") %></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<% @investments.each do |investment| %>
|
||||||
|
<tr id="<%= dom_id(investment) %>" class="budget_investment">
|
||||||
|
<td class="text-right">
|
||||||
|
<strong><%= investment.id %></strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<%= link_to investment.title, admin_budget_budget_investment_path(budget_id: @budget.id, id: investment.id, params: Budget::Investment.filter_params(params)) %>
|
||||||
|
</td>
|
||||||
|
<td class="small">
|
||||||
|
<% if investment.administrator.present? %>
|
||||||
|
<span title="<%= t('admin.budget_investments.index.assigned_admin') %>"><%= investment.administrator.name %></span>
|
||||||
|
<% else %>
|
||||||
|
<%= t("admin.budget_investments.index.no_admin_assigned") %>
|
||||||
|
<% end %>
|
||||||
|
</td>
|
||||||
|
<td class="small">
|
||||||
|
<% if investment.valuators.size == 0 %>
|
||||||
|
<%= t("admin.budget_investments.index.no_valuators_assigned") %>
|
||||||
|
<% else %>
|
||||||
|
<%= investment.valuators.collect(&:description_or_name).join(', ') %>
|
||||||
|
<% end %>
|
||||||
|
</td>
|
||||||
|
<td class="small">
|
||||||
|
<%= investment.heading.name %>
|
||||||
|
</td>
|
||||||
|
<td class="small">
|
||||||
|
<%= t("admin.budget_investments.index.feasibility.#{investment.feasibility}",
|
||||||
|
price: investment.formatted_price)
|
||||||
|
%>
|
||||||
|
</td>
|
||||||
|
<td class="small text-center">
|
||||||
|
<%= investment.valuation_finished? ? t('shared.yes'): t('shared.no') %>
|
||||||
|
</td>
|
||||||
|
<td class="small">
|
||||||
|
<% if investment.selected? %>
|
||||||
|
<%= link_to toggle_selection_admin_budget_budget_investment_path(@budget,
|
||||||
|
investment,
|
||||||
|
filter: params[:filter],
|
||||||
|
page: params[:page]),
|
||||||
|
method: :patch,
|
||||||
|
remote: true,
|
||||||
|
class: "button small expanded" do %>
|
||||||
|
<%= t("admin.budget_investments.index.selected") %>
|
||||||
|
<% end %>
|
||||||
|
<% elsif investment.feasible? && investment.valuation_finished? %>
|
||||||
|
<%= link_to toggle_selection_admin_budget_budget_investment_path(@budget,
|
||||||
|
investment,
|
||||||
|
filter: params[:filter],
|
||||||
|
page: params[:page]),
|
||||||
|
method: :patch,
|
||||||
|
remote: true,
|
||||||
|
class: "button small hollow expanded" do %>
|
||||||
|
<%= t("admin.budget_investments.index.select") %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<%= paginate @investments %>
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<div class="callout primary float-right">
|
||||||
|
<%= t "admin.budget_investments.show.info", budget_name: @budget.name, group_name: @investment.group.name, id: @investment.id %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<h1 class="inline-block"><%= @investment.title %></h1>
|
||||||
|
|
||||||
|
<div class="row small-collapse spending-proposal-info">
|
||||||
|
<div class="small-12 medium-4 column">
|
||||||
|
<p title="<%= t("admin.budget_investments.show.group") %>: <%= @investment.group.name %>">
|
||||||
|
<strong><%= t("admin.budget_investments.show.heading") %>:</strong>
|
||||||
|
<%= @investment.heading.name %>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small-12 medium-4 column">
|
||||||
|
<p>
|
||||||
|
<strong><%= t("admin.budget_investments.show.by") %>:</strong>
|
||||||
|
<%= link_to @investment.author.name, admin_user_path(@investment.author) %>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small-12 medium-4 column">
|
||||||
|
<p>
|
||||||
|
<strong><%= t("admin.budget_investments.show.sent") %>:</strong>
|
||||||
|
<%= l @investment.created_at, format: :datetime %>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% if @investment.external_url.present? %>
|
||||||
|
<p><%= text_with_links @investment.external_url %> <span class="icon-external small"></span></p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= safe_html_with_links @investment.description %>
|
||||||
70
app/views/admin/budget_investments/edit.html.erb
Normal file
70
app/views/admin/budget_investments/edit.html.erb
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<%= link_to admin_budget_budget_investment_path(@budget, @investment, Budget::Investment.filter_params(params)), class: 'back' do %>
|
||||||
|
<span class="icon-angle-left"></span> <%= t("shared.back") %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= form_for @investment,
|
||||||
|
url: admin_budget_budget_investment_path(@budget, @investment) do |f| %>
|
||||||
|
|
||||||
|
<% Budget::Investment.filter_params(params).each do |filter_name, filter_value| %>
|
||||||
|
<%= hidden_field_tag filter_name, filter_value %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="small-12 column">
|
||||||
|
<%= f.text_field :title, maxlength: Budget::Investment.title_max_length %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ckeditor small-12 column">
|
||||||
|
<%= f.cktext_area :description, maxlength: Budget::Investment.description_max_length, ckeditor: { language: I18n.locale } %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small-12 column">
|
||||||
|
<%= f.text_field :external_url %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small-12 column">
|
||||||
|
<%= f.select :heading_id, budget_heading_select_options(@budget), include_blank: t("admin.budget_investments.edit.select_heading") %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 id="classification"><%= t("admin.budget_investments.edit.classification") %></h2>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="small-12 column">
|
||||||
|
<%= f.select(:administrator_id,
|
||||||
|
@admins.collect{ |a| [a.name_and_email, a.id ] },
|
||||||
|
{ include_blank: t("admin.budget_investments.edit.undefined") }) %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="small-12 column">
|
||||||
|
<%= f.label :tag_list, t("admin.budget_investments.edit.tags") %>
|
||||||
|
<div class="tags">
|
||||||
|
<% @tags.each do |tag| %>
|
||||||
|
<a class="js-add-tag-link"><%= tag.name %></a>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<%= f.text_field :valuation_tag_list,
|
||||||
|
value: @investment.tag_list_on(:valuation).sort.join(','),
|
||||||
|
label: false,
|
||||||
|
placeholder: t("admin.budget_investments.edit.tags_placeholder"),
|
||||||
|
class: 'js-tag-list' %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small-12 column">
|
||||||
|
<%= f.label :valuator_ids, t("admin.budget_investments.edit.assigned_valuators") %>
|
||||||
|
|
||||||
|
<%= f.collection_check_boxes :valuator_ids, @valuators, :id, :email do |b| %>
|
||||||
|
<%= b.label(title: valuator_label(b.object)) { b.check_box + truncate(b.object.description_or_email, length: 60) } %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="clear">
|
||||||
|
<%= f.submit(class: "button", value: t("admin.budget_investments.edit.submit_button")) %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<%# render 'valuation/budget_investments/written_by_valuators' %>
|
||||||
44
app/views/admin/budget_investments/index.html.erb
Normal file
44
app/views/admin/budget_investments/index.html.erb
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<h2 class="inline-block"><%= @budget.name %> - <%= t("admin.budget_investments.index.title") %></h2>
|
||||||
|
|
||||||
|
<div class="row margin">
|
||||||
|
<%= form_tag admin_budget_budget_investments_path(budget: @budget), method: :get, enforce_utf8: false do %>
|
||||||
|
<div class="small-12 medium-3 column">
|
||||||
|
<%= select_tag :administrator_id,
|
||||||
|
options_for_select(admin_select_options, params[:administrator_id]),
|
||||||
|
{ prompt: t("admin.budget_investments.index.administrator_filter_all"),
|
||||||
|
label: false,
|
||||||
|
class: "js-submit-on-change" } %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small-12 medium-3 column">
|
||||||
|
<%= select_tag :valuator_id,
|
||||||
|
options_for_select(valuator_select_options, params[:valuator_id]),
|
||||||
|
{ prompt: t("admin.budget_investments.index.valuator_filter_all"),
|
||||||
|
label: false,
|
||||||
|
class: "js-submit-on-change" } %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small-12 medium-3 column">
|
||||||
|
<%= select_tag :heading_id,
|
||||||
|
options_for_select(budget_heading_select_options(@budget), params[:heading_id]),
|
||||||
|
{ prompt: t("admin.budget_investments.index.heading_filter_all"),
|
||||||
|
label: false,
|
||||||
|
class: "js-submit-on-change" } %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small-12 medium-3 column">
|
||||||
|
<%= select_tag :tag_name,
|
||||||
|
options_for_select(spending_proposal_tags_select_options, params[:tag_name]),
|
||||||
|
{ prompt: t("admin.budget_investments.index.tags_filter_all"),
|
||||||
|
label: false,
|
||||||
|
class: "js-submit-on-change" } %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= render '/shared/filter_subnav', i18n_namespace: "admin.budget_investments.index" %>
|
||||||
|
|
||||||
|
<div id="investments">
|
||||||
|
<%= render '/admin/budget_investments/investments' %>
|
||||||
|
</div>
|
||||||
|
|
||||||
49
app/views/admin/budget_investments/show.html.erb
Normal file
49
app/views/admin/budget_investments/show.html.erb
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<%= link_to admin_budget_budget_investments_path(Budget::Investment.filter_params(params)), data: {no_turbolink: true} do %>
|
||||||
|
<span class="icon-angle-left"></span> <%= t("shared.back") %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= render 'written_by_author' %>
|
||||||
|
|
||||||
|
<%= link_to t("admin.budget_investments.show.edit"),
|
||||||
|
edit_admin_budget_budget_investment_path(@budget, @investment,
|
||||||
|
Budget::Investment.filter_params(params)) %>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2 id="classification"><%= t("admin.budget_investments.show.classification") %></h2>
|
||||||
|
|
||||||
|
<p><strong><%= t("admin.budget_investments.show.assigned_admin") %>:</strong>
|
||||||
|
<%= @investment.administrator.try(:name_and_email) || t("admin.budget_investments.show.undefined") %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p id="tags">
|
||||||
|
<strong><%= t("admin.budget_investments.show.tags") %>:</strong>
|
||||||
|
|
||||||
|
<%= @investment.tags_on(:valuation).pluck(:name).join(', ') %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p id="assigned_valuators">
|
||||||
|
<strong><%= t("admin.budget_investments.show.assigned_valuators") %>:</strong>
|
||||||
|
<% if @investment.valuators.any? %>
|
||||||
|
<%= @investment.valuators.collect(&:name_and_email).join(', ') %>
|
||||||
|
<% else %>
|
||||||
|
<%= t("admin.budget_investments.show.undefined") %>
|
||||||
|
<% end %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<%= link_to t("admin.budget_investments.show.edit_classification"),
|
||||||
|
edit_admin_budget_budget_investment_path(@budget, @investment,
|
||||||
|
{anchor: 'classification'}.merge(Budget::Investment.filter_params(params))) %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2><%= t("admin.budget_investments.show.dossier") %></h2>
|
||||||
|
|
||||||
|
<%= render 'valuation/budget_investments/written_by_valuators' %>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<%= link_to t("admin.budget_investments.show.edit_dossier"), edit_valuation_budget_budget_investment_path(@budget, @investment) %>
|
||||||
|
</p>
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
$("#investments").html('<%= j render("admin/budget_investments/investments") %>');
|
||||||
20
app/views/admin/budgets/_form.html.erb
Normal file
20
app/views/admin/budgets/_form.html.erb
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<%= form_for [:admin, @budget] do |f| %>
|
||||||
|
|
||||||
|
<%= f.text_field :name, maxlength: Budget.title_max_length %>
|
||||||
|
|
||||||
|
<% Budget::PHASES.each do |phase| %>
|
||||||
|
<div class="margin-top">
|
||||||
|
<%= f.cktext_area "description_#{phase}", maxlength: Budget.description_max_length, ckeditor: { language: I18n.locale } %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div class="row margin-top">
|
||||||
|
<div class="small-12 medium-9 column">
|
||||||
|
<%= f.select :phase, budget_phases_select_options %>
|
||||||
|
</div>
|
||||||
|
<div class="small-12 medium-3 column">
|
||||||
|
<%= f.select :currency_symbol, budget_currency_symbol_select_options %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<%= f.submit nil, class: "button success" %>
|
||||||
|
<% end %>
|
||||||
67
app/views/admin/budgets/_group.html.erb
Normal file
67
app/views/admin/budgets/_group.html.erb
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th colspan="3" class="with-button">
|
||||||
|
<%= group.name %>
|
||||||
|
<%= link_to t("admin.budgets.form.add_heading"), "#", class: "button float-right js-toggle-link", data: { "toggle-selector" => "#group-#{group.id}-new-heading-form" } %>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<% if headings.blank? %>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3">
|
||||||
|
<div class="callout primary">
|
||||||
|
<%= t("admin.budgets.form.no_heading") %>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% else %>
|
||||||
|
<tr>
|
||||||
|
<th><%= t("admin.budgets.form.table_heading") %></th>
|
||||||
|
<th><%= t("admin.budgets.form.table_amount") %></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<!-- new heading form -->
|
||||||
|
<tr id="group-<%= group.id %>-new-heading-form" style="display:none">
|
||||||
|
<td colspan="3">
|
||||||
|
<%= form_for [:admin, @budget, group, Budget::Heading.new], remote: true do |f| %>
|
||||||
|
<label><%= t("admin.budgets.form.heading") %></label>
|
||||||
|
<%= f.text_field :name,
|
||||||
|
label: false,
|
||||||
|
maxlength: 50,
|
||||||
|
placeholder: t("admin.budgets.form.heading") %>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="small-12 medium-6 column">
|
||||||
|
<label><%= t("admin.budgets.form.amount") %></label>
|
||||||
|
<%= f.text_field :price,
|
||||||
|
label: false,
|
||||||
|
maxlength: 8,
|
||||||
|
placeholder: t("admin.budgets.form.amount") %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= f.submit t("admin.budgets.form.save_heading"), class: "button success" %>
|
||||||
|
<% end %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- /. new heading form -->
|
||||||
|
<!-- headings list -->
|
||||||
|
<% headings.each do |heading| %>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<%= heading.name %>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<%= heading.price %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
<!-- /. headings list -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
32
app/views/admin/budgets/_groups.html.erb
Normal file
32
app/views/admin/budgets/_groups.html.erb
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<h3 class="inline-block"><%= t('admin.budgets.show.groups', count: groups.count) %></h3>
|
||||||
|
<% if groups.blank? %>
|
||||||
|
<div class="callout primary">
|
||||||
|
<%= t("admin.budgets.form.no_groups") %>
|
||||||
|
<strong><%= link_to t("admin.budgets.form.add_group"), "#",
|
||||||
|
class: "js-toggle-link",
|
||||||
|
data: { "toggle-selector" => "#new-group-form" } %></strong>
|
||||||
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<%= link_to t("admin.budgets.form.add_group"), "#", class: "button float-right js-toggle-link", data: { "toggle-selector" => "#new-group-form" } %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= form_for [:admin, @budget, Budget::Group.new], html: {id: "new-group-form", style: "display:none"}, remote: true do |f| %>
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-label">
|
||||||
|
<label><%= f.label :name,t("admin.budgets.form.group") %></label>
|
||||||
|
</span>
|
||||||
|
<%= f.text_field :name,
|
||||||
|
label: false,
|
||||||
|
maxlength: 50,
|
||||||
|
placeholder: t("admin.budgets.form.group") %>
|
||||||
|
<div class="input-group-button">
|
||||||
|
<%= f.submit t("admin.budgets.form.create_group"), class: "button success" %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% groups.each do |group| %>
|
||||||
|
<div id="<%= dom_id(group) %>">
|
||||||
|
<%= render "admin/budgets/group", group: group, headings: group.headings %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
9
app/views/admin/budgets/edit.html.erb
Normal file
9
app/views/admin/budgets/edit.html.erb
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<%= back_link_to admin_budgets_path %>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="small-12 medium-9 column">
|
||||||
|
<h2><%= t("admin.budgets.edit.title") %></h2>
|
||||||
|
|
||||||
|
<%= render '/admin/budgets/form' %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
44
app/views/admin/budgets/index.html.erb
Normal file
44
app/views/admin/budgets/index.html.erb
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<h2 class="inline-block"><%= t("admin.budgets.index.title") %></h2>
|
||||||
|
|
||||||
|
<%= link_to t("admin.budgets.index.new_link"),
|
||||||
|
new_admin_budget_path,
|
||||||
|
class: "button float-right margin-right" %>
|
||||||
|
|
||||||
|
<%= render 'shared/filter_subnav', i18n_namespace: "admin.budgets.index" %>
|
||||||
|
|
||||||
|
<h3><%= page_entries_info @budgets %></h3>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><%= t("admin.budgets.index.table_name") %></th>
|
||||||
|
<th><%= t("admin.budgets.index.table_phase") %></th>
|
||||||
|
<th><%= t("admin.budgets.index.table_investments") %></th>
|
||||||
|
<th><%= t("admin.budgets.index.table_edit_groups") %></th>
|
||||||
|
<th><%= t("admin.budgets.index.table_edit_budget") %></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% @budgets.each do |budget| %>
|
||||||
|
<tr id="<%= dom_id(budget) %>" class="budget">
|
||||||
|
<td>
|
||||||
|
<%= budget.name %>
|
||||||
|
</td>
|
||||||
|
<td class="small">
|
||||||
|
<%= t("budgets.phase.#{budget.phase}") %>
|
||||||
|
</td>
|
||||||
|
<td class="small">
|
||||||
|
<%= link_to t("admin.budgets.index.budget_investments"), admin_budget_budget_investments_path(budget_id: budget.id) %>
|
||||||
|
</td>
|
||||||
|
<td class="small">
|
||||||
|
<%= link_to t("admin.budgets.index.edit_groups"), admin_budget_path(budget) %>
|
||||||
|
</td>
|
||||||
|
<td class="small">
|
||||||
|
<%= link_to t("admin.budgets.index.edit_budget"), edit_admin_budget_path(budget) %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<%= paginate @budgets %>
|
||||||
7
app/views/admin/budgets/new.html.erb
Normal file
7
app/views/admin/budgets/new.html.erb
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="small-12 medium-9 column">
|
||||||
|
<h2><%= t("admin.budgets.new.title") %></h2>
|
||||||
|
|
||||||
|
<%= render '/admin/budgets/form' %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
7
app/views/admin/budgets/show.html.erb
Normal file
7
app/views/admin/budgets/show.html.erb
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<%= back_link_to admin_budgets_path %>
|
||||||
|
|
||||||
|
<h2><%= @budget.name %></h2>
|
||||||
|
|
||||||
|
<div id="<%= dom_id @budget %>_groups">
|
||||||
|
<%= render "groups", groups: @budget.groups %>
|
||||||
|
</div>
|
||||||
25
app/views/admin/shared/_budget_investment_search.html.erb
Normal file
25
app/views/admin/shared/_budget_investment_search.html.erb
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<%= form_for(Budget::Investment.new, url: url, as: :budget_investment, method: :get) do |f| %>
|
||||||
|
<div class="row">
|
||||||
|
<div class="small-12 medium-6 column">
|
||||||
|
<%= text_field_tag :search, "" %>
|
||||||
|
</div>
|
||||||
|
<div class="small-12 medium-6 column">
|
||||||
|
<%= select_tag :heading_id,
|
||||||
|
options_for_select(budget_heading_select_options(@budget),
|
||||||
|
params[:heading_id]),
|
||||||
|
include_blank: true
|
||||||
|
%>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="small-12 medium-6 column">
|
||||||
|
<%= check_box_tag :unfeasible, "1", params[:unfeasible].present? %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="form-inline small-12 medium-3 column end">
|
||||||
|
<%= f.submit t("shared.search"), class: "button" %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
54
app/views/budgets/ballot/_ballot.html.erb
Normal file
54
app/views/budgets/ballot/_ballot.html.erb
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<div class="expanded budget no-margin-top padding">
|
||||||
|
<div class="row">
|
||||||
|
<%= render 'shared/back_link' %>
|
||||||
|
|
||||||
|
<h1 class="text-center"><%= t("budgets.ballots.show.title") %></h1>
|
||||||
|
|
||||||
|
<div class="small-12 medium-8 column small-centered text-center">
|
||||||
|
<h2>
|
||||||
|
<%= t("budgets.ballots.show.voted_html",
|
||||||
|
count: @ballot.investments.count) %>
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
<small>
|
||||||
|
<%= t("budgets.ballots.show.voted_info_html") %>
|
||||||
|
</small>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row ballot">
|
||||||
|
<div class="margin-top">
|
||||||
|
<% @ballot.groups.each do |group| %>
|
||||||
|
<div id="<%= dom_id(group) %>"
|
||||||
|
class="small-12 medium-6 column">
|
||||||
|
<h3 class="subtitle">
|
||||||
|
<%= group.name %> - <%= group.headings.first.name %>
|
||||||
|
</h3>
|
||||||
|
<% if @ballot.has_lines_in_group?(group) %>
|
||||||
|
<h4 class="amount-spent text-right">
|
||||||
|
<%= t("budgets.ballots.show.amount_spent") %>
|
||||||
|
<span>
|
||||||
|
<%= @ballot.formatted_amount_spent(@ballot.heading_for_group(group)) %>
|
||||||
|
</span>
|
||||||
|
</h4>
|
||||||
|
<% else %>
|
||||||
|
<p>
|
||||||
|
<%= t("budgets.ballots.show.zero") %><br>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<ul class="ballot-list">
|
||||||
|
<%= render partial: 'budgets/ballot/investment',
|
||||||
|
collection: @ballot.investments.by_group(group.id) %>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4>
|
||||||
|
<%= t("budgets.ballots.show.remaining",
|
||||||
|
amount: @ballot.formatted_amount_available(@ballot.heading_for_group(group))).html_safe %>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
14
app/views/budgets/ballot/_investment.html.erb
Normal file
14
app/views/budgets/ballot/_investment.html.erb
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<li id="<%= dom_id(investment) %>">
|
||||||
|
<%= link_to investment.title, budget_investment_path(@budget, investment) %>
|
||||||
|
<span><%= investment.formatted_price %></span>
|
||||||
|
|
||||||
|
<% if @budget.balloting? %>
|
||||||
|
<%= link_to budget_ballot_line_path(@budget, id: investment.id),
|
||||||
|
title: t('budgets.ballots.show.remove'),
|
||||||
|
class: "remove-investment-project",
|
||||||
|
method: :delete,
|
||||||
|
remote: true do %>
|
||||||
|
<span class="icon-x"></span>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</li>
|
||||||
16
app/views/budgets/ballot/_investment_for_sidebar.html.erb
Normal file
16
app/views/budgets/ballot/_investment_for_sidebar.html.erb
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<li id="<%= dom_id(investment) %>_sidebar">
|
||||||
|
<%= investment.title %>
|
||||||
|
<span><%= investment.formatted_price %></span>
|
||||||
|
|
||||||
|
<% if @budget.balloting? %>
|
||||||
|
<%= link_to budget_ballot_line_url(id: investment.id,
|
||||||
|
investments_ids: investment_ids),
|
||||||
|
title: t('budgets.ballots.show.remove'),
|
||||||
|
class: "remove-investment-project",
|
||||||
|
method: :delete,
|
||||||
|
remote: true do %>
|
||||||
|
<span class="sr-only"><%= t('budgets.ballots.show.remove') %></span>
|
||||||
|
<span class="icon-x delete"></span>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</li>
|
||||||
29
app/views/budgets/ballot/_progress_bar.html.erb
Normal file
29
app/views/budgets/ballot/_progress_bar.html.erb
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<span class="total-amount">
|
||||||
|
<%= @budget.formatted_heading_price(@heading) %>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="progress" role="progressbar" tabindex="0"
|
||||||
|
id="progress"
|
||||||
|
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
|
||||||
|
<div class="progress-meter"
|
||||||
|
style="width:
|
||||||
|
<%= progress_bar_width(@budget.heading_price(@heading),
|
||||||
|
@ballot.amount_spent(@heading)) %>">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="progress spent-amount-progress" role="progressbar" tabindex="0"
|
||||||
|
aria-valuenow="20" aria-valuemin="0" aria-valuetext="25 percent" aria-valuemax="100">
|
||||||
|
<span class="progress-meter spent-amount-meter"
|
||||||
|
style="width:
|
||||||
|
<%= progress_bar_width(@budget.heading_price(@heading),
|
||||||
|
@ballot.amount_spent(@heading)) %>">
|
||||||
|
<p id="amount-spent" class="progress-meter-text spent-amount-text">
|
||||||
|
<%= @ballot.formatted_amount_spent(@heading) %>
|
||||||
|
<span id="amount-available" class="amount-available">
|
||||||
|
<%= t("budgets.progress_bar.available") %>
|
||||||
|
<span><%= @ballot.formatted_amount_available(@heading) %></span>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
8
app/views/budgets/ballot/lines/_refresh_ballots.js.erb
Normal file
8
app/views/budgets/ballot/lines/_refresh_ballots.js.erb
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<% if @investments.present? %>
|
||||||
|
<% @investments.each do |investment| %>
|
||||||
|
$("#<%= dom_id(investment) %>_ballot").html('<%= j render("/budgets/investments/ballot",
|
||||||
|
investment: investment,
|
||||||
|
investment_ids: investment_ids,
|
||||||
|
ballot: ballot) %>');
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
11
app/views/budgets/ballot/lines/create.js.erb
Normal file
11
app/views/budgets/ballot/lines/create.js.erb
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
$("#progress_bar").html('<%= j render("/budgets/ballot/progress_bar", ballot: @ballot) %>');
|
||||||
|
$("#sidebar").html('<%= j render("/budgets/investments/sidebar") %>');
|
||||||
|
$("#<%= dom_id(@investment) %>_ballot").html('<%= j render("/budgets/investments/ballot",
|
||||||
|
investment: @investment,
|
||||||
|
investment_ids: @investment_ids,
|
||||||
|
ballot: @ballot) %>');
|
||||||
|
|
||||||
|
<%= render 'refresh_ballots',
|
||||||
|
investment: @investment,
|
||||||
|
investment_ids: @investment_ids,
|
||||||
|
ballot: @ballot %>
|
||||||
12
app/views/budgets/ballot/lines/destroy.js.erb
Normal file
12
app/views/budgets/ballot/lines/destroy.js.erb
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
$("#progress_bar").html('<%= j render("budgets/ballot/progress_bar", ballot: @ballot) %>');
|
||||||
|
$("#sidebar").html('<%= j render("budgets/investments/sidebar") %>');
|
||||||
|
$("#ballot").html('<%= j render("budgets/ballot/ballot") %>')
|
||||||
|
|
||||||
|
$("#<%= dom_id(@investment) %>_ballot").html('<%= j render("/budgets/investments/ballot",
|
||||||
|
investment: @investment,
|
||||||
|
investment_ids: @investment_ids,
|
||||||
|
ballot: @ballot) %>');
|
||||||
|
<%= render 'refresh_ballots',
|
||||||
|
investment: @investment,
|
||||||
|
investment_ids: @investment_ids,
|
||||||
|
ballot: @ballot %>
|
||||||
2
app/views/budgets/ballot/lines/new.js.erb
Normal file
2
app/views/budgets/ballot/lines/new.js.erb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
$("#<%= dom_id(@spending_proposal) %>_ballot").html('<%= j render("spending_proposals/ballot", spending_proposal: @spending_proposal) %>');
|
||||||
|
$(".no-supports-allowed").show();
|
||||||
3
app/views/budgets/ballot/show.html.erb
Normal file
3
app/views/budgets/ballot/show.html.erb
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<div id="ballot">
|
||||||
|
<%= render "budgets/ballot/ballot" %>
|
||||||
|
</div>
|
||||||
31
app/views/budgets/groups/show.html.erb
Normal file
31
app/views/budgets/groups/show.html.erb
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<div class="expanded budget no-margin-top">
|
||||||
|
<div class="row">
|
||||||
|
<div class="small-12 medium-9 column padding">
|
||||||
|
<%= back_link_to budget_path(@budget) %>
|
||||||
|
<h2><%= t("budgets.groups.show.title") %></h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row margin-top">
|
||||||
|
<div id="select-district" class="small-12 medium-7 column select-district">
|
||||||
|
<div class="row">
|
||||||
|
<% @group.headings.each_slice(7) do |slice| %>
|
||||||
|
<div class="small-6 medium-4 column end">
|
||||||
|
<% slice.each do |heading| %>
|
||||||
|
<span id="<%= dom_id(heading) %>"
|
||||||
|
class="<%= css_for_ballot_heading(heading) %>">
|
||||||
|
<%= link_to heading.name,
|
||||||
|
budget_investments_path(heading_id: heading.id),
|
||||||
|
data: { no_turbolink: true } %><br>
|
||||||
|
</span>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="medium-5 column show-for-medium text-center">
|
||||||
|
<%= image_tag "map.jpg" %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
30
app/views/budgets/index.html.erb
Normal file
30
app/views/budgets/index.html.erb
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<div class="expanded budget no-margin-top padding">
|
||||||
|
<div class="row">
|
||||||
|
<div class="small-12 column">
|
||||||
|
<h1><%= t('budgets.index.title') %></h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row margin-top">
|
||||||
|
<div class="small-12 medium-9 column">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<th><%= Budget.human_attribute_name(:name) %></th>
|
||||||
|
<th><%= Budget.human_attribute_name(:phase) %></th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% @budgets.each do |budget| %>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<%= link_to budget.name, budget %>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<%= budget.translated_phase %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
59
app/views/budgets/investments/_ballot.html.erb
Normal file
59
app/views/budgets/investments/_ballot.html.erb
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<% reason = investment.reason_for_not_being_ballotable_by(current_user, ballot) %>
|
||||||
|
<div class="js-participation supports ballot">
|
||||||
|
<% if ballot.has_investment?(investment) %>
|
||||||
|
|
||||||
|
<div class="remove supported inline-block">
|
||||||
|
<span class="icon-check-circle"
|
||||||
|
title="<%= t("budgets.investments.investment.already_added") %>">
|
||||||
|
</span>
|
||||||
|
<p class="investment-project-amount">
|
||||||
|
<%= investment.formatted_price %>
|
||||||
|
</p>
|
||||||
|
<% if investment.should_show_ballots? %>
|
||||||
|
<%= link_to t('budgets.ballots.show.remove'),
|
||||||
|
budget_ballot_line_path(id: investment.id,
|
||||||
|
budget_id: investment.budget_id,
|
||||||
|
investments_ids: investment_ids),
|
||||||
|
class: "delete small expanded",
|
||||||
|
method: :delete,
|
||||||
|
remote: true %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% else %>
|
||||||
|
|
||||||
|
<div class="add in-favor">
|
||||||
|
<p class="investment-project-amount">
|
||||||
|
<%= investment.formatted_price %>
|
||||||
|
</p>
|
||||||
|
<% if investment.should_show_ballots? %>
|
||||||
|
<%= link_to t("budgets.investments.investment.add"),
|
||||||
|
budget_ballot_lines_url(investment_id: investment.id,
|
||||||
|
budget_id: investment.budget_id,
|
||||||
|
investments_ids: investment_ids),
|
||||||
|
class: "button button-support small expanded",
|
||||||
|
title: t('budgets.investments.investment.support_title'),
|
||||||
|
method: :post,
|
||||||
|
remote: true %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if reason.present? && !ballot.has_investment?(investment) %>
|
||||||
|
|
||||||
|
<div class="js-participation-not-allowed participation-not-allowed" style='display:none'>
|
||||||
|
<p>
|
||||||
|
<%= t("budgets.ballots.reasons_for_not_balloting.#{reason}",
|
||||||
|
verify_account: link_to(t("votes.verify_account"), verification_path),
|
||||||
|
signin: link_to(t("votes.signin"), new_user_session_path),
|
||||||
|
signup: link_to(t("votes.signup"), new_user_registration_path),
|
||||||
|
my_heading: link_to(investment.heading.name,
|
||||||
|
budget_investments_path(budget_id: investment.budget_id,
|
||||||
|
heading_id: investment.heading_id))
|
||||||
|
).html_safe %>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
11
app/views/budgets/investments/_categories.html.erb
Normal file
11
app/views/budgets/investments/_categories.html.erb
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<div class="sidebar-divider"></div>
|
||||||
|
<h2 class="sidebar-title"><%= t("shared.tags_cloud.categories") %></h2>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<ul id="categories" class="no-bullet categories">
|
||||||
|
<% @categories.each do |category| %>
|
||||||
|
<li class="inline-block">
|
||||||
|
<%= link_to category.name,
|
||||||
|
budget_investments_path(@budget, search: category.name) %></li>
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
69
app/views/budgets/investments/_form.html.erb
Normal file
69
app/views/budgets/investments/_form.html.erb
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<%= form_for(@investment, url: form_url, method: :post) do |f| %>
|
||||||
|
<%= render 'shared/errors', resource: @investment %>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="small-12 medium-8 column">
|
||||||
|
<%= f.select :heading_id, budget_heading_select_options(@budget), {include_blank: true, } %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small-12 column">
|
||||||
|
<%= f.text_field :title, maxlength: SpendingProposal.title_max_length %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= f.invisible_captcha :subtitle %>
|
||||||
|
|
||||||
|
<div class="ckeditor small-12 column">
|
||||||
|
<%= f.cktext_area :description, maxlength: SpendingProposal.description_max_length, ckeditor: { language: I18n.locale } %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small-12 column">
|
||||||
|
<%= f.text_field :external_url %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small-12 column">
|
||||||
|
<%= f.text_field :location %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small-12 column">
|
||||||
|
<%= f.text_field :organization_name %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small-12 column">
|
||||||
|
<%= f.label :tag_list, t("budgets.investments.form.tags_label") %>
|
||||||
|
<p class="note"><%= t("budgets.investments.form.tags_instructions") %></p>
|
||||||
|
|
||||||
|
<div id="category_tags" class="tags">
|
||||||
|
<%= f.label :category_tag_list, t("budgets.investments.form.tag_category_label") %>
|
||||||
|
<% @categories.each do |tag| %>
|
||||||
|
<a class="js-add-tag-link"><%= tag.name %></a>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<%= f.text_field :tag_list, value: @investment.tag_list.to_s,
|
||||||
|
label: false,
|
||||||
|
placeholder: t("budgets.investments.form.tags_placeholder"),
|
||||||
|
class: 'js-tag-list' %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<% unless current_user.manager? %>
|
||||||
|
|
||||||
|
<div class="small-12 column">
|
||||||
|
<%= f.label :terms_of_service do %>
|
||||||
|
<%= f.check_box :terms_of_service, title: t('form.accept_terms_title'), label: false %>
|
||||||
|
<span class="checkbox">
|
||||||
|
<%= t("form.accept_terms",
|
||||||
|
policy: link_to(t("form.policy"), "/privacy", target: "blank"),
|
||||||
|
conditions: link_to(t("form.conditions"), "/conditions", target: "blank")).html_safe %>
|
||||||
|
</span>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div class="actions small-12 medium-6 large-4 end column">
|
||||||
|
<%= f.submit(nil, class: "button expanded") %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
58
app/views/budgets/investments/_header.html.erb
Normal file
58
app/views/budgets/investments/_header.html.erb
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<% if @heading.present? %>
|
||||||
|
<section class="no-margin-top margin-bottom">
|
||||||
|
<div class="expanded jumbo-budget budget-heading padding">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="small-12 column">
|
||||||
|
<%= back_link_to budget_group_path(@budget, @heading.group) %>
|
||||||
|
|
||||||
|
<% if can? :show, @ballot %>
|
||||||
|
<%= link_to t("budgets.investments.header.check_ballot"),
|
||||||
|
budget_ballot_path(@budget),
|
||||||
|
class: "button float-right" %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row progress-votes">
|
||||||
|
<div class="small-12 column">
|
||||||
|
<div class="progress-bar-nav" data-fixed-bar>
|
||||||
|
<h1 class="inline-block margin-top"><%= @heading.name %></h1>
|
||||||
|
<% if can? :show, @ballot %>
|
||||||
|
<div id="check-ballot" style="display: none;">
|
||||||
|
<%= link_to t("budgets.investments.header.check_ballot"),
|
||||||
|
budget_ballot_path(@budget) %>
|
||||||
|
</div>
|
||||||
|
<% if @ballot.valid_heading?(@heading) %>
|
||||||
|
<div id="progress_bar" class="no-margin-top">
|
||||||
|
<%= render 'budgets/ballot/progress_bar' %>
|
||||||
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<br>
|
||||||
|
<p class="callout warning inline-block">
|
||||||
|
<%= t("budgets.investments.header.different_heading_assigned_html",
|
||||||
|
heading_link: link_to(
|
||||||
|
@assigned_heading.name,
|
||||||
|
budget_investments_path(@budget, heading: @assigned_heading))
|
||||||
|
) %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
<% else %>
|
||||||
|
<h2><%= @budget.formatted_heading_price(@heading) %></h2>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<% else %>
|
||||||
|
<div class="expanded jumbo-budget padding no-margin-top margin-bottom">
|
||||||
|
<div class="row">
|
||||||
|
<div class="small-12 column">
|
||||||
|
<%= back_link_to budget_path(@budget) %>
|
||||||
|
|
||||||
|
<h1><%= t('budgets.investments.index.title') %></h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
75
app/views/budgets/investments/_investment.html.erb
Normal file
75
app/views/budgets/investments/_investment.html.erb
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<div id="<%= dom_id(investment) %>" class="budget-investment clear">
|
||||||
|
<div class="panel">
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="small-12 medium-9 column">
|
||||||
|
<div class="budget-investment-content">
|
||||||
|
|
||||||
|
<% cache [locale_and_user_status(investment), 'index', investment, investment.author] do %>
|
||||||
|
<span class="label-budget-investment float-left"><%= t("budgets.investments.investment.title") %></span>
|
||||||
|
<span class="icon-budget"></span>
|
||||||
|
<h3><%= link_to investment.title, namespaced_budget_investment_path(investment) %></h3>
|
||||||
|
<p class="investment-project-info">
|
||||||
|
|
||||||
|
<%= l investment.created_at.to_date %>
|
||||||
|
|
||||||
|
<% if investment.author.hidden? || investment.author.erased? %>
|
||||||
|
<span class="bullet"> • </span>
|
||||||
|
<span class="author">
|
||||||
|
<%= t("budgets.investments.show.author_deleted") %>
|
||||||
|
</span>
|
||||||
|
<% else %>
|
||||||
|
<span class="bullet"> • </span>
|
||||||
|
<span class="author">
|
||||||
|
<%= investment.author.name %>
|
||||||
|
</span>
|
||||||
|
<% if investment.author.official? %>
|
||||||
|
<span class="bullet"> • </span>
|
||||||
|
<span class="label round level-<%= investment.author.official_level %>">
|
||||||
|
<%= investment.author.official_position %>
|
||||||
|
</span>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<span class="bullet"> • </span>
|
||||||
|
<%= investment.heading.name %>
|
||||||
|
</p>
|
||||||
|
<div class="investment-project-description">
|
||||||
|
<p><%= investment.description %></p>
|
||||||
|
<div class="truncate"></div>
|
||||||
|
</div>
|
||||||
|
<%= render "shared/tags", taggable: investment, limit: 5 %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% unless investment.unfeasible? %>
|
||||||
|
|
||||||
|
<% if investment.should_show_votes? %>
|
||||||
|
|
||||||
|
<div id="<%= dom_id(investment) %>_votes"
|
||||||
|
class="small-12 medium-3 column text-center">
|
||||||
|
<%= render partial: '/budgets/investments/votes', locals: {
|
||||||
|
investment: investment,
|
||||||
|
investment_votes: investment_votes,
|
||||||
|
vote_url: namespaced_budget_investment_vote_path(investment, value: 'yes')
|
||||||
|
} %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% elsif investment.should_show_ballots? %>
|
||||||
|
|
||||||
|
<div id="<%= dom_id(investment) %>_ballot"
|
||||||
|
class="small-12 medium-3 column text-center">
|
||||||
|
<%= render partial: '/budgets/investments/ballot', locals: {
|
||||||
|
investment: investment,
|
||||||
|
investment_ids: investment_ids,
|
||||||
|
ballot: ballot
|
||||||
|
} %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
102
app/views/budgets/investments/_investment_show.html.erb
Normal file
102
app/views/budgets/investments/_investment_show.html.erb
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<section class="budget-investment-show" id="<%= dom_id(investment) %>">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="small-12 medium-9 column">
|
||||||
|
<%= back_link_to budget_investments_path(investment.budget) %>
|
||||||
|
|
||||||
|
<h1><%= investment.title %></h1>
|
||||||
|
|
||||||
|
<div class="budget-investment-info">
|
||||||
|
<%= render '/shared/author_info', resource: investment %>
|
||||||
|
|
||||||
|
<span class="bullet"> • </span>
|
||||||
|
<%= l investment.created_at.to_date %>
|
||||||
|
<span class="bullet"> • </span>
|
||||||
|
<%= investment.heading.name %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<p id="investment_code">
|
||||||
|
<%= t("budgets.investments.show.code_html", code: investment.id) %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<% if investment.location.present? %>
|
||||||
|
<p>
|
||||||
|
<%= t("budgets.investments.show.location_html", location: investment.location) %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if investment.organization_name.present? %>
|
||||||
|
<p>
|
||||||
|
<%= t("budgets.investments.show.organization_name_html", name: investment.organization_name) %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= render 'shared/tags', taggable: investment %>
|
||||||
|
|
||||||
|
<%= safe_html_with_links investment.description.html_safe %>
|
||||||
|
|
||||||
|
<% if investment.external_url.present? %>
|
||||||
|
<div class="document-link">
|
||||||
|
<%= text_with_links investment.external_url %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if investment.unfeasible? && investment.unfeasibility_explanation.present? %>
|
||||||
|
<h2><%= t('budgets.investments.show.unfeasibility_explanation') %></h2>
|
||||||
|
<p><%= investment.unfeasibility_explanation %></p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if investment.feasible? && investment.price_explanation.present? %>
|
||||||
|
<h2><%= t('budgets.investments.show.price_explanation') %></h2>
|
||||||
|
<p><%= investment.price_explanation %></p>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% if investment.should_show_aside? %>
|
||||||
|
<aside class="small-12 medium-3 column">
|
||||||
|
<div class="sidebar-divider"></div>
|
||||||
|
<h2><%= t("votes.supports") %></h2>
|
||||||
|
<div class="text-center">
|
||||||
|
|
||||||
|
<% if investment.should_show_votes? %>
|
||||||
|
<div id="<%= dom_id(investment) %>_votes">
|
||||||
|
<%= render partial: '/budgets/investments/votes', locals: {
|
||||||
|
investment: investment,
|
||||||
|
investment_votes: investment_votes,
|
||||||
|
vote_url: vote_budget_investment_path(investment.budget, investment, value: 'yes')
|
||||||
|
} %>
|
||||||
|
</div>
|
||||||
|
<% elsif investment.should_show_ballots? %>
|
||||||
|
<div id="<%= dom_id(investment) %>_ballot">
|
||||||
|
<%= render partial: 'ballot', locals: {
|
||||||
|
investment: investment,
|
||||||
|
investment_ids: investment_ids,
|
||||||
|
ballot: ballot,
|
||||||
|
} %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-divider"></div>
|
||||||
|
<h2><%= t("budgets.investments.show.share") %></h2>
|
||||||
|
<div class="social-share-full">
|
||||||
|
<%= social_share_button_tag("#{investment.title} #{setting['twitter_hashtag']}") %>
|
||||||
|
<% if browser.device.mobile? %>
|
||||||
|
<a href="whatsapp://send?text=<%= investment.title %> <%= budget_investment_url(budget_id: investment.budget_id, id: investment.id) %>" data-action="share/whatsapp/share">
|
||||||
|
<span class="icon-whatsapp whatsapp"></span>
|
||||||
|
</a>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
<% else %>
|
||||||
|
<div class="small-12 medium-3 column">
|
||||||
|
<div class="float-right">
|
||||||
|
<span class="label-budget-investment float-left"><%= t("budgets.investments.show.title") %></span>
|
||||||
|
<span class="icon-budget"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
48
app/views/budgets/investments/_sidebar.html.erb
Normal file
48
app/views/budgets/investments/_sidebar.html.erb
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<div class="clear"></div>
|
||||||
|
|
||||||
|
<% if can?(:create, Budget::Investment.new(budget: @budget)) %>
|
||||||
|
<% if current_user && current_user.level_two_or_three_verified? %>
|
||||||
|
<%= link_to t("budgets.investments.index.sidebar.create"), new_budget_investment_path, class: "button budget expanded" %>
|
||||||
|
<% else %>
|
||||||
|
<div class="callout warning">
|
||||||
|
<%= t("budgets.investments.index.sidebar.verified_only",
|
||||||
|
verify: link_to(t("budgets.investments.index.sidebar.verify_account"), verification_path)).html_safe %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if @budget.accepting? %>
|
||||||
|
<%= render "shared/tag_cloud", taggable: 'budget/investment' %>
|
||||||
|
<%= render 'categories' %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
|
||||||
|
<% if @heading && can?(:show, @ballot) %>
|
||||||
|
|
||||||
|
<div class="sidebar-divider"></div>
|
||||||
|
|
||||||
|
<h2 class="sidebar-title"><%= t("budgets.investments.index.sidebar.my_ballot") %></h2>
|
||||||
|
<% if @ballot.investments.by_heading(@heading.id).count > 0 %>
|
||||||
|
<p>
|
||||||
|
<em>
|
||||||
|
<%= t("budgets.investments.index.sidebar.voted_html",
|
||||||
|
count: @ballot.investments.by_heading(@heading.id).count,
|
||||||
|
amount_spent: @ballot.formatted_amount_spent(@heading)) %>
|
||||||
|
</em>
|
||||||
|
</p>
|
||||||
|
<% else %>
|
||||||
|
<p><strong><%= t("budgets.investments.index.sidebar.zero") %></strong></p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<ul class="ballot-list">
|
||||||
|
<% if @heading %>
|
||||||
|
<% @ballot.investments.by_heading(@heading.id).each do |investment| %>
|
||||||
|
<%= render 'budgets/ballot/investment_for_sidebar',
|
||||||
|
investment: investment,
|
||||||
|
investment_ids: @investment_ids %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p class="callout primary"><%= t("budgets.investments.index.sidebar.voted_info") %></p>
|
||||||
|
<% end %>
|
||||||
46
app/views/budgets/investments/_votes.html.erb
Normal file
46
app/views/budgets/investments/_votes.html.erb
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<% reason = investment.reason_for_not_being_selectable_by(current_user) %>
|
||||||
|
<% voting_allowed = true unless reason.presence == :not_voting_allowed %>
|
||||||
|
<% user_voted_for = voted_for?(investment_votes, investment) %>
|
||||||
|
|
||||||
|
<div class="supports js-participation">
|
||||||
|
|
||||||
|
<span class="total-supports <%= 'no-button' unless voting_allowed || user_voted_for %>">
|
||||||
|
<%= t("budgets.investments.investment.supports", count: investment.total_votes) %>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="in-favor js-in-favor">
|
||||||
|
<% if user_voted_for %>
|
||||||
|
<div class="supported callout success">
|
||||||
|
<%= t("budgets.investments.investment.already_supported") %>
|
||||||
|
</div>
|
||||||
|
<% elsif investment.should_show_votes? %>
|
||||||
|
|
||||||
|
<%= link_to vote_url,
|
||||||
|
class: "button button-support small expanded",
|
||||||
|
title: t('budgets.investments.investment.support_title'),
|
||||||
|
method: "post",
|
||||||
|
remote: true,
|
||||||
|
"aria-hidden" => css_for_aria_hidden(reason) do %>
|
||||||
|
<%= t("budgets.investments.investment.give_support") %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% if reason.present? && !user_voted_for %>
|
||||||
|
<div class="js-participation-not-allowed participation-not-allowed" style='display:none' aria-hidden="false">
|
||||||
|
<p>
|
||||||
|
<%= t("votes.budget_investments.#{reason}",
|
||||||
|
verify_account: link_to(t("votes.verify_account"), verification_path),
|
||||||
|
signin: link_to(t("votes.signin"), new_user_session_path),
|
||||||
|
signup: link_to(t("votes.signup"), new_user_registration_path)
|
||||||
|
).html_safe %>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if user_voted_for && setting['twitter_handle'] %>
|
||||||
|
<div class="share-supported">
|
||||||
|
<%= social_share_button_tag("#{investment.title} #{setting['twitter_hashtag']}", url: budget_investment_url(budget_id: investment.budget_id, id: investment.id), via: setting['twitter_handle']) %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
59
app/views/budgets/investments/index.html.erb
Normal file
59
app/views/budgets/investments/index.html.erb
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<% provide :title do %><%= t('budgets.investments.index.title') %><% end %>
|
||||||
|
<% content_for :header_addon do %>
|
||||||
|
<%= render "shared/search_form",
|
||||||
|
search_path: budget_investments_path(budget_id: @budget.id, page: 1),
|
||||||
|
i18n_namespace: "budgets.investments.index.search_form" %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<main id="budget-investments-main">
|
||||||
|
|
||||||
|
<% unless params[:search].present? %>
|
||||||
|
<%= render '/budgets/investments/header' %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div class="wrap row">
|
||||||
|
<div id="budget-investments" class="budget-investments-list small-12 medium-9 column">
|
||||||
|
|
||||||
|
<div class="small-12 search-results margin-bottom">
|
||||||
|
|
||||||
|
<% if params[:unfeasible].present? %>
|
||||||
|
<h2><%= t("budgets.investments.index.unfeasible") %></h2>
|
||||||
|
<p>
|
||||||
|
<%= t("budgets.investments.index.unfeasible_text",
|
||||||
|
definitions: link_to(t("budgets.investments.index.unfeasible_text_definitions"), "https://decide.madrid.es/participatory_budget_info#20")).html_safe %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= content_tag(:h2, t("budgets.investments.index.by_heading", heading: @heading.name)) if @heading.present? %>
|
||||||
|
<% if params[:search].present? %>
|
||||||
|
<h2>
|
||||||
|
<%= page_entries_info @investments %>
|
||||||
|
<%= t("budgets.investments.index.search_results", count: @investments.size, search_term: params[:search]) %>
|
||||||
|
</h2>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= render('shared/order_links', i18n_namespace: "budgets.investments.index") unless params[:unfeasible].present? %>
|
||||||
|
|
||||||
|
<% @investments.each do |investment| %>
|
||||||
|
<%= render partial: '/budgets/investments/investment', locals: {
|
||||||
|
investment: investment,
|
||||||
|
investment_ids: @investment_ids,
|
||||||
|
investment_votes: @investment_votes,
|
||||||
|
ballot: @ballot
|
||||||
|
} %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= paginate @investments %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small-12 medium-3 column">
|
||||||
|
<aside class="margin-bottom">
|
||||||
|
<div id="sidebar">
|
||||||
|
<%= render '/budgets/investments/sidebar' %>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
7
app/views/budgets/investments/new.html.erb
Normal file
7
app/views/budgets/investments/new.html.erb
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<div class="budget-investment-new row">
|
||||||
|
<div class="small-12 medium-9 column">
|
||||||
|
<h1><%= t("management.budget_investments.create") %></h1>
|
||||||
|
|
||||||
|
<%= render '/budgets/investments/form', form_url: budget_investments_path(@budget) %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
10
app/views/budgets/investments/show.html.erb
Normal file
10
app/views/budgets/investments/show.html.erb
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<% provide :title do %><%= @investment.title %><% end %>
|
||||||
|
|
||||||
|
<%= render partial: '/budgets/investments/investment_show', locals: {
|
||||||
|
investment: @investment,
|
||||||
|
investment_ids: @investment_ids,
|
||||||
|
investment_votes: @investment_votes,
|
||||||
|
ballot: @ballot
|
||||||
|
} %>
|
||||||
|
|
||||||
|
<%= render partial: '/comments/comment_tree', locals: { comment_tree: @comment_tree, comment_flags: @comment_flags } %>
|
||||||
4
app/views/budgets/investments/vote.js.erb
Normal file
4
app/views/budgets/investments/vote.js.erb
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
$("#<%= dom_id(@investment) %>_votes").html('<%= j render("/budgets/investments/votes",
|
||||||
|
investment: @investment,
|
||||||
|
investment_votes: @investment_votes,
|
||||||
|
vote_url: namespaced_budget_investment_vote_path(@investment, value: 'yes')) %>');
|
||||||
63
app/views/budgets/show.html.erb
Normal file
63
app/views/budgets/show.html.erb
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<div class="expanded budget no-margin-top">
|
||||||
|
<div class="row" data-equalizer>
|
||||||
|
<div class="small-12 medium-9 column padding" data-equalizer-watch>
|
||||||
|
<%= back_link_to budgets_path %>
|
||||||
|
|
||||||
|
<h1><%= @budget.name %></h1>
|
||||||
|
|
||||||
|
<%= @budget.description %>
|
||||||
|
</div>
|
||||||
|
<div class="small-12 medium-3 column info padding" data-equalizer-watch>
|
||||||
|
<p>
|
||||||
|
<strong><%= t('budgets.show.phase') %></strong>
|
||||||
|
<br>
|
||||||
|
<%= t("budgets.phase.#{@budget.phase}") %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<% if can?(:create, Budget::Investment.new(budget: @budget))%>
|
||||||
|
<% if current_user %>
|
||||||
|
<% if current_user.level_two_or_three_verified? %>
|
||||||
|
<%= link_to t("budgets.investments.index.sidebar.create"), new_budget_investment_path(@budget), class: "button margin-top expanded" %>
|
||||||
|
<% else %>
|
||||||
|
<div class="callout warning margin-top">
|
||||||
|
<%= t("budgets.investments.index.sidebar.verified_only",
|
||||||
|
verify: link_to(t("budgets.investments.index.sidebar.verify_account"), verification_path)).html_safe %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% else %>
|
||||||
|
<div class="callout primary margin-top">
|
||||||
|
<%= t("budgets.investments.index.sidebar.not_logged_in",
|
||||||
|
sign_in: link_to(t("budgets.investments.index.sidebar.sign_in"), new_user_session_path),
|
||||||
|
sign_up: link_to(t("budgets.investments.index.sidebar.sign_up"), new_user_registration_path)).html_safe %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row margin-top">
|
||||||
|
<div class="small-12 medium-9 column">
|
||||||
|
<table class="table-fixed">
|
||||||
|
<thead>
|
||||||
|
<th><%= t('budgets.show.group') %></th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% @budget.groups.each do |group| %>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<% if group.headings.count == 1 %>
|
||||||
|
<%= link_to group.name,
|
||||||
|
budget_investments_path(@budget, heading_id: group.headings.first.id),
|
||||||
|
data: { no_turbolink: true } %>
|
||||||
|
<% else %>
|
||||||
|
<%= link_to group.name, budget_group_path(@budget, group) %>
|
||||||
|
<% end %>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<% cache [locale_and_user_status(comment), comment, commentable_cache_key(comment.commentable), comment.author, (@comment_flags[comment.id] if @comment_flags)] do %>
|
<% comment_flags ||= @comment_flags %>
|
||||||
|
<% cache [locale_and_user_status(comment), comment, commentable_cache_key(comment.commentable), comment.author, (comment_flags[comment.id] if comment_flags)] do %>
|
||||||
<ul id="<%= dom_id(comment) %>" class="comment no-bullet small-12">
|
<ul id="<%= dom_id(comment) %>" class="comment no-bullet small-12">
|
||||||
<li class="comment-body">
|
<li class="comment-body">
|
||||||
<% if comment.hidden? || comment.user.hidden? %>
|
<% if comment.hidden? || comment.user.hidden? %>
|
||||||
|
|||||||
34
app/views/comments/_comment_tree.html.erb
Normal file
34
app/views/comments/_comment_tree.html.erb
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<% commentable = comment_tree.commentable %>
|
||||||
|
<% current_order = comment_tree.order %>
|
||||||
|
|
||||||
|
<% cache [locale_and_user_status, current_order, commentable_cache_key(commentable), comment_tree.comments, comment_tree.comment_authors, commentable.comments_count, comment_flags] do %>
|
||||||
|
<section class="expanded comments">
|
||||||
|
<div class="row">
|
||||||
|
<div id="comments" class="small-12 column">
|
||||||
|
<h2>
|
||||||
|
<%= t("debates.show.comments_title") %>
|
||||||
|
<span class="js-comments-count">(<%= commentable.comments_count %>)</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<%= render 'shared/wide_order_selector', i18n_namespace: "comments" %>
|
||||||
|
|
||||||
|
<% if user_signed_in? %>
|
||||||
|
<%= render 'comments/form', {commentable: commentable, parent_id: nil, toggeable: false} %>
|
||||||
|
<% else %>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div data-alert class="callout primary">
|
||||||
|
<%= t("debates.show.login_to_comment",
|
||||||
|
signin: link_to(t("votes.signin"), new_user_session_path),
|
||||||
|
signup: link_to(t("votes.signup"), new_user_registration_path)).html_safe %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% comment_tree.root_comments.each do |comment| %>
|
||||||
|
<%= render 'comments/comment', {comment: comment, comment_flags: comment_flags} %>
|
||||||
|
<% end %>
|
||||||
|
<%= paginate comment_tree.root_comments %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<% end %>
|
||||||
31
app/views/comments/_commentable_tree.html.erb
Normal file
31
app/views/comments/_commentable_tree.html.erb
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<% cache [locale_and_user_status, @current_order, commentable_cache_key(@investment), @comment_tree.comments, @comment_tree.comment_authors, @investment.comments_count, @comment_flags] do %>
|
||||||
|
<section class="expanded comments">
|
||||||
|
<div class="row">
|
||||||
|
<div id="comments" class="small-12 column">
|
||||||
|
<h2>
|
||||||
|
<%= t("debates.show.comments_title") %>
|
||||||
|
<span class="js-comments-count">(<%= @investment.comments_count %>)</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<%= render 'shared/wide_order_selector', i18n_namespace: "comments" %>
|
||||||
|
|
||||||
|
<% if user_signed_in? %>
|
||||||
|
<%= render 'comments/form', {commentable: @investment, parent_id: nil, toggeable: false} %>
|
||||||
|
<% else %>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div data-alert class="callout primary">
|
||||||
|
<%= t("debates.show.login_to_comment",
|
||||||
|
signin: link_to(t("votes.signin"), new_user_session_path),
|
||||||
|
signup: link_to(t("votes.signup"), new_user_registration_path)).html_safe %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% @comment_tree.root_comments.each do |comment| %>
|
||||||
|
<%= render 'comments/comment', comment: comment %>
|
||||||
|
<% end %>
|
||||||
|
<%= paginate @comment_tree.root_comments %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<% end %>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user