Merge branch 'master' into user-recomendations
11
Gemfile.lock
@@ -199,7 +199,7 @@ GEM
|
||||
terminal-table (>= 1.5.1)
|
||||
initialjs-rails (0.2.0.5)
|
||||
railties (>= 3.1, < 6.0)
|
||||
invisible_captcha (0.9.2)
|
||||
invisible_captcha (0.9.3)
|
||||
rails (>= 3.2.0)
|
||||
jquery-fileupload-rails (0.4.7)
|
||||
actionpack (>= 3.1)
|
||||
@@ -251,7 +251,7 @@ GEM
|
||||
mime-types-data (3.2016.0521)
|
||||
mimemagic (0.3.2)
|
||||
mini_portile2 (2.2.0)
|
||||
minitest (5.10.2)
|
||||
minitest (5.10.3)
|
||||
mixlib-cli (1.7.0)
|
||||
mixlib-config (2.2.4)
|
||||
multi_json (1.12.1)
|
||||
@@ -368,7 +368,7 @@ GEM
|
||||
rspec-mocks (3.6.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-rails (3.6.0)
|
||||
rspec-rails (3.6.1)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
@@ -398,7 +398,7 @@ GEM
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
sprockets-rails (>= 2.0, < 4.0)
|
||||
tilt (>= 1.1, < 3)
|
||||
savon (2.11.1)
|
||||
savon (2.11.2)
|
||||
akami (~> 1.2)
|
||||
builder (>= 2.1.2)
|
||||
gyoku (~> 1.2)
|
||||
@@ -430,7 +430,7 @@ GEM
|
||||
babel-source (>= 5.8.11)
|
||||
babel-transpiler
|
||||
sprockets (>= 3.0.0)
|
||||
sprockets-rails (3.2.0)
|
||||
sprockets-rails (3.2.1)
|
||||
actionpack (>= 4.0)
|
||||
activesupport (>= 4.0)
|
||||
sprockets (>= 3.0.0)
|
||||
@@ -565,6 +565,5 @@ DEPENDENCIES
|
||||
web-console (~> 3.3.0)
|
||||
whenever (~> 0.9.7)
|
||||
|
||||
|
||||
BUNDLED WITH
|
||||
1.15.3
|
||||
|
||||
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.9 KiB |
@@ -9,6 +9,7 @@
|
||||
@import 'pages';
|
||||
@import 'legislation';
|
||||
@import 'legislation_process';
|
||||
@import 'community';
|
||||
@import 'custom';
|
||||
@import 'c3';
|
||||
@import 'annotator.min';
|
||||
|
||||
44
app/assets/stylesheets/community.scss
Normal file
@@ -0,0 +1,44 @@
|
||||
.communities-show {
|
||||
.button.disabled, .button[disabled] {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.wide-order-selector {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.panel {
|
||||
min-height: auto;
|
||||
margin: 0.375rem 0;
|
||||
|
||||
.button {
|
||||
margin-top: $line-height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.communities-participant {
|
||||
|
||||
.comment-body {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
margin-right: $line-height;
|
||||
margin-bottom: $line-height;
|
||||
}
|
||||
}
|
||||
|
||||
.topic-show {
|
||||
|
||||
p,
|
||||
ul li {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.comments {
|
||||
|
||||
.first-comment {
|
||||
margin-top: $line-height;
|
||||
margin-bottom: $line-height;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,37 +13,29 @@
|
||||
//
|
||||
|
||||
// 01. Utils
|
||||
// -----------------
|
||||
// ---------
|
||||
|
||||
$grey-heading: #e6e6e6;
|
||||
$border-dark: darken($border, 10%);
|
||||
|
||||
.grey-heading {
|
||||
background: #e6e6e6;
|
||||
background: $grey-heading;
|
||||
}
|
||||
|
||||
$epigraph-font-size: rem-calc(15);
|
||||
$epigraph-line-height: rem-calc(22);
|
||||
|
||||
// 02. Hero
|
||||
// -----------------
|
||||
// --------
|
||||
|
||||
.legislation-hero {
|
||||
padding-top: 1.5rem;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
padding-top: 3.5rem;
|
||||
}
|
||||
|
||||
h4 {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
margin-left: 0;
|
||||
|
||||
li::before {
|
||||
vertical-align: text-bottom;
|
||||
padding-right: 0.5rem;
|
||||
content: '■';
|
||||
color: #8aa8be;
|
||||
content: '■';
|
||||
padding-right: $line-height / 4;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,79 +44,33 @@ $epigraph-line-height: rem-calc(22);
|
||||
}
|
||||
|
||||
.debate-add-info {
|
||||
margin-top: 3rem;
|
||||
padding-top: 4rem;
|
||||
border-top: 1px solid darken($border, 10%);
|
||||
border-top: 1px solid $border-dark;
|
||||
margin-top: $line-height;
|
||||
padding-top: $line-height;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.debate-info-wrapper {
|
||||
|
||||
h2 {
|
||||
font-size: $lead-font-size;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.half-gradient {
|
||||
background: #e6e6e6;
|
||||
background: linear-gradient(to bottom, #e6e6e6 0%, #e6e6e6 50%, #fff 50%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e6e6e6', endColorstr='#fff', GradientType=0);
|
||||
}
|
||||
|
||||
.text-center .button {
|
||||
background: $brand;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.headline {
|
||||
margin-bottom: 1rem;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
margin-bottom: 4rem;
|
||||
|
||||
}
|
||||
.title {
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin-bottom: 1rem;
|
||||
|
||||
p {
|
||||
font-size: $epigraph-font-size;
|
||||
line-height: $epigraph-line-height;
|
||||
}
|
||||
|
||||
ul {
|
||||
font-size: $epigraph-font-size;
|
||||
line-height: $epigraph-line-height;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 1rem;
|
||||
|
||||
p {
|
||||
display: inline;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: $base-font-size;
|
||||
}
|
||||
}
|
||||
|
||||
.button-subscribe {
|
||||
margin-top: 1rem;
|
||||
margin-top: $line-height;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
margin-top: $line-height * 2;
|
||||
padding: 0.5em 1em;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@@ -132,8 +78,8 @@ $epigraph-line-height: rem-calc(22);
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
font-size: $small-font-size;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&:hover h3 {
|
||||
@@ -143,41 +89,21 @@ $epigraph-line-height: rem-calc(22);
|
||||
}
|
||||
|
||||
// 03. Legislation process navigation
|
||||
// -----------------
|
||||
// ----------------------------------
|
||||
|
||||
.legislation-process-categories {
|
||||
position: relative;
|
||||
|
||||
.legislation-process-list {
|
||||
border-bottom: 1px solid $medium-gray;
|
||||
margin: 0 1rem 1rem;
|
||||
padding-top: 4rem;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
position: relative;
|
||||
max-width: 75rem;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 0;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
svg {
|
||||
position: absolute;
|
||||
top: 1.25rem;
|
||||
|
||||
@include breakpoint(1280px) {
|
||||
transform: rotate(-6deg);
|
||||
left: -1rem;
|
||||
}
|
||||
}
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
@@ -187,6 +113,10 @@ $epigraph-line-height: rem-calc(22);
|
||||
transition: all 0.4s;
|
||||
border-bottom: 2px solid transparent;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
margin-left: $line-height * 2;
|
||||
}
|
||||
|
||||
&:first-of-type {
|
||||
margin-left: 0;
|
||||
}
|
||||
@@ -197,29 +127,25 @@ $epigraph-line-height: rem-calc(22);
|
||||
border-bottom: 2px solid $brand;
|
||||
}
|
||||
|
||||
@media (min-width: 950px) {
|
||||
margin: 0 0 0 3rem;
|
||||
}
|
||||
|
||||
a,
|
||||
h4 {
|
||||
display: block;
|
||||
color: #6d6d6d;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
&:hover,
|
||||
&:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
a {
|
||||
&:hover,
|
||||
&:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
@include breakpoint(medium) {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,7 +157,8 @@ $epigraph-line-height: rem-calc(22);
|
||||
}
|
||||
|
||||
// 04. Debate list
|
||||
// -----------------
|
||||
// ----------------
|
||||
|
||||
.debate-chooser {
|
||||
padding: 2rem 1rem;
|
||||
|
||||
@@ -277,38 +204,43 @@ $epigraph-line-height: rem-calc(22);
|
||||
}
|
||||
|
||||
// 05. Debate quiz
|
||||
// -----------------
|
||||
// ---------------
|
||||
|
||||
.debate-questions {
|
||||
|
||||
.comments {
|
||||
margin-top: 4rem;
|
||||
margin-top: $line-height * 2.5;
|
||||
}
|
||||
|
||||
.quiz-header {
|
||||
margin-bottom: 2rem;
|
||||
margin-bottom: $line-height;
|
||||
|
||||
.quiz-title,
|
||||
.quiz-next {
|
||||
padding: 1rem;
|
||||
height: 6rem;
|
||||
padding: $line-height;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
height: $line-height * 4;
|
||||
}
|
||||
}
|
||||
|
||||
.quiz-title {
|
||||
background: #e5ecf2;
|
||||
|
||||
.quiz-header-title {
|
||||
font-size: $small-font-size;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0;
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
font-size: $small-font-size;
|
||||
}
|
||||
}
|
||||
|
||||
h4 a {
|
||||
color: $brand;
|
||||
}
|
||||
|
||||
h4 a:hover {
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.quiz-next-link {
|
||||
@@ -318,57 +250,49 @@ $epigraph-line-height: rem-calc(22);
|
||||
&:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.quiz-next {
|
||||
background: #ccdbe5;
|
||||
font-weight: 700;
|
||||
color: $brand;
|
||||
font-size: $small-font-size;
|
||||
text-align: right;
|
||||
text-transform: uppercase;
|
||||
transition: background 0.25s ease-out, background 0.25s ease-out;
|
||||
.quiz-next {
|
||||
background: #ccdbe5;
|
||||
color: $brand;
|
||||
font-size: $small-font-size;
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
text-transform: uppercase;
|
||||
transition: background 0.25s ease-out, background 0.25s ease-out;
|
||||
|
||||
.icon-angle-right {
|
||||
vertical-align: sub;
|
||||
}
|
||||
.icon-angle-right {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
text-decoration: none;
|
||||
background: $brand;
|
||||
color: #fff;
|
||||
|
||||
.icon-angle-right {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
&:hover,
|
||||
&:active {
|
||||
background: $brand;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.quiz-question {
|
||||
margin-bottom: 2rem;
|
||||
margin-bottom: $line-height;
|
||||
}
|
||||
|
||||
.debate-questions {
|
||||
position: relative;
|
||||
list-style: none;
|
||||
|
||||
.participation-not-allowed {
|
||||
padding-bottom: 3rem;
|
||||
}
|
||||
|
||||
.control {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
color: #555;
|
||||
cursor: pointer;
|
||||
background: #fff;
|
||||
border: 1px solid $border;
|
||||
border-radius: 4px;
|
||||
padding: 0.75rem 2.5rem;
|
||||
margin-right: 1.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
border-radius: rem-calc(4);
|
||||
color: #555;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
margin-bottom: $line-height / 2;
|
||||
margin-right: $line-height;
|
||||
padding: $line-height / 2 $line-height * 2;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.active {
|
||||
@@ -409,14 +333,15 @@ $epigraph-line-height: rem-calc(22);
|
||||
}
|
||||
|
||||
// 06. Legislation draft
|
||||
// -----------------
|
||||
// ---------------------
|
||||
|
||||
.debate-draft {
|
||||
padding: 10rem 2rem 15rem;
|
||||
display: block;
|
||||
background: #f2f2f2;
|
||||
|
||||
button {
|
||||
height: 90px;
|
||||
height: rem-calc(90);
|
||||
|
||||
h3 {
|
||||
margin-bottom: 0;
|
||||
@@ -430,7 +355,8 @@ $epigraph-line-height: rem-calc(22);
|
||||
}
|
||||
|
||||
// 07. Legislation allegations
|
||||
// -----------------
|
||||
// ---------------------------
|
||||
|
||||
.legislation-allegation {
|
||||
padding-top: 1rem;
|
||||
|
||||
@@ -449,12 +375,12 @@ $epigraph-line-height: rem-calc(22);
|
||||
.button-circle {
|
||||
line-height: 0;
|
||||
padding: 0;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
width: rem-calc(30);
|
||||
height: rem-calc(30);
|
||||
border-radius: 50%;
|
||||
|
||||
span {
|
||||
padding-left: 1px;
|
||||
padding-left: rem-calc(1);
|
||||
|
||||
&::before {
|
||||
line-height: 1.55;
|
||||
@@ -580,7 +506,7 @@ $epigraph-line-height: rem-calc(22);
|
||||
.calc-comments {
|
||||
cursor: pointer;
|
||||
background: #f2f2f2;
|
||||
width: 50px;
|
||||
width: rem-calc(50);
|
||||
|
||||
.draft-panel {
|
||||
.panel-title {
|
||||
@@ -733,7 +659,7 @@ $epigraph-line-height: rem-calc(22);
|
||||
|
||||
.comments-on {
|
||||
.calc-index {
|
||||
width: 50px;
|
||||
width: rem-calc(50);
|
||||
background: #f2f2f2;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -797,11 +723,11 @@ $epigraph-line-height: rem-calc(22);
|
||||
|
||||
.comments-box-container {
|
||||
position: absolute;
|
||||
top: 230px;
|
||||
top: rem-calc(230);
|
||||
}
|
||||
|
||||
.comment-box {
|
||||
width: 375px;
|
||||
width: rem-calc(375);
|
||||
padding: 1rem;
|
||||
background: #f9f9f9;
|
||||
border: 1px solid $border;
|
||||
@@ -852,7 +778,7 @@ $epigraph-line-height: rem-calc(22);
|
||||
|
||||
.participation-not-allowed {
|
||||
font-size: 0.875rem;
|
||||
height: 50px;
|
||||
height: rem-calc(50);
|
||||
padding: 0.85rem 0.75rem;
|
||||
top: -18px;
|
||||
}
|
||||
@@ -891,7 +817,7 @@ $epigraph-line-height: rem-calc(22);
|
||||
border-right: 1px solid #d0d0d0;
|
||||
border-left: 1px solid #d0d0d0;
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
height: rem-calc(200);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,8 @@
|
||||
// 03. Content
|
||||
// ----------------------
|
||||
|
||||
.more-info-content {
|
||||
.more-info-content,
|
||||
.communities-show {
|
||||
|
||||
h3 {
|
||||
color: $brand;
|
||||
|
||||
@@ -249,7 +249,9 @@
|
||||
.proposal-form,
|
||||
.budget-investment-form,
|
||||
.spending-proposal-form,
|
||||
.document-form {
|
||||
.document-form,
|
||||
.topic-new,
|
||||
.topic-form {
|
||||
|
||||
.icon-debates,
|
||||
.icon-proposals,
|
||||
@@ -298,6 +300,8 @@
|
||||
}
|
||||
|
||||
.proposal-form,
|
||||
.topic-form,
|
||||
.topic-new,
|
||||
.document-form {
|
||||
|
||||
.recommendations li::before {
|
||||
@@ -316,7 +320,9 @@
|
||||
.debate-quiz,
|
||||
.budget-investment-show,
|
||||
.draft-panels,
|
||||
.debate-questions {
|
||||
.debate-questions,
|
||||
.communities-show,
|
||||
.topic-show {
|
||||
|
||||
p {
|
||||
word-wrap: break-word;
|
||||
@@ -350,7 +356,8 @@
|
||||
.debate-info,
|
||||
.proposal-info,
|
||||
.investment-project-info,
|
||||
.budget-investment-show {
|
||||
.budget-investment-show,
|
||||
.topic-info {
|
||||
clear: both;
|
||||
color: $text-medium;
|
||||
font-size: $small-font-size;
|
||||
@@ -627,7 +634,8 @@
|
||||
.proposal,
|
||||
.investment-project,
|
||||
.budget-investment,
|
||||
.legislation {
|
||||
.legislation,
|
||||
.communities-show {
|
||||
margin: $line-height / 4 0;
|
||||
|
||||
.panel {
|
||||
@@ -699,7 +707,8 @@
|
||||
.debate-info,
|
||||
.proposal-info,
|
||||
.investment-project-info,
|
||||
.budget-investment-info {
|
||||
.budget-investment-info,
|
||||
.topic-info {
|
||||
color: $text-medium;
|
||||
font-size: $small-font-size;
|
||||
margin: rem-calc(6) 0 0;
|
||||
@@ -885,17 +894,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.help-link {
|
||||
margin-left: $line-height;
|
||||
position: relative;
|
||||
.help-header {
|
||||
|
||||
&::before {
|
||||
color: $link;
|
||||
content: '\4e';
|
||||
font-family: 'icons';
|
||||
position: absolute;
|
||||
left: -24px;
|
||||
top: -2px;
|
||||
h1 {
|
||||
font-size: rem-calc(24);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,35 +32,6 @@ class Admin::Poll::OfficerAssignmentsController < Admin::BaseController
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@officer_assignment = ::Poll::OfficerAssignment.new(booth_assignment: @booth_assignment,
|
||||
officer_id: create_params[:officer_id],
|
||||
date: create_params[:date])
|
||||
@officer_assignment.final = true if @officer_assignment.date > @booth_assignment.poll.ends_at.to_date
|
||||
|
||||
if @officer_assignment.save
|
||||
notice = t("admin.poll_officer_assignments.flash.create")
|
||||
else
|
||||
notice = t("admin.poll_officer_assignments.flash.error_create")
|
||||
end
|
||||
|
||||
redirect_params = { poll_id: create_params[:poll_id], officer_id: create_params[:officer_id] }
|
||||
redirect_to by_officer_admin_poll_officer_assignments_path(redirect_params), notice: notice
|
||||
end
|
||||
|
||||
def destroy
|
||||
@officer_assignment = ::Poll::OfficerAssignment.includes(:booth_assignment).find(params[:id])
|
||||
|
||||
if @officer_assignment.destroy
|
||||
notice = t("admin.poll_officer_assignments.flash.destroy")
|
||||
else
|
||||
notice = t("admin.poll_officer_assignments.flash.error_destroy")
|
||||
end
|
||||
|
||||
redirect_params = { poll_id: @officer_assignment.poll_id, officer_id: @officer_assignment.officer_id }
|
||||
redirect_to by_officer_admin_poll_officer_assignments_path(redirect_params), notice: notice
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def officer_assignment_params
|
||||
|
||||
53
app/controllers/admin/poll/shifts_controller.rb
Normal file
@@ -0,0 +1,53 @@
|
||||
class Admin::Poll::ShiftsController < Admin::BaseController
|
||||
|
||||
before_action :load_booth
|
||||
before_action :load_polls
|
||||
|
||||
def new
|
||||
load_officers
|
||||
load_shifts
|
||||
@shift = ::Poll::Shift.new
|
||||
end
|
||||
|
||||
def create
|
||||
@shift = ::Poll::Shift.new(shift_params)
|
||||
if @shift.save
|
||||
notice = t("admin.poll_shifts.flash.create")
|
||||
redirect_to new_admin_booth_shift_path(@shift.booth), notice: notice
|
||||
else
|
||||
load_officers
|
||||
load_shifts
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@shift = Poll::Shift.find(params[:id])
|
||||
@shift.destroy
|
||||
notice = t("admin.poll_shifts.flash.destroy")
|
||||
redirect_to new_admin_booth_shift_path(@booth), notice: notice
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_booth
|
||||
@booth = ::Poll::Booth.find(params[:booth_id])
|
||||
end
|
||||
|
||||
def load_polls
|
||||
@polls = ::Poll.current_or_incoming
|
||||
end
|
||||
|
||||
def load_officers
|
||||
@officers = ::Poll::Officer.all
|
||||
end
|
||||
|
||||
def load_shifts
|
||||
@shifts = @booth.shifts
|
||||
end
|
||||
|
||||
def shift_params
|
||||
params.require(:shift).permit(:booth_id, :officer_id, :date)
|
||||
end
|
||||
|
||||
end
|
||||
30
app/controllers/communities_controller.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
class CommunitiesController < ApplicationController
|
||||
|
||||
before_action :set_order, :set_community, :load_topics, :load_participants, only: :show
|
||||
|
||||
has_orders %w{newest most_commented oldest}, only: :show
|
||||
|
||||
skip_authorization_check
|
||||
|
||||
def show
|
||||
redirect_to root_path unless Setting['feature.community'].present?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_order
|
||||
@order = params[:order].present? ? params[:order] : "newest"
|
||||
end
|
||||
|
||||
def set_community
|
||||
@community = Community.find(params[:id])
|
||||
end
|
||||
|
||||
def load_topics
|
||||
@topics = @community.topics.send("sort_by_#{@order}").page(params[:page])
|
||||
end
|
||||
|
||||
def load_participants
|
||||
@participants = @community.participants
|
||||
end
|
||||
end
|
||||
55
app/controllers/topics_controller.rb
Normal file
@@ -0,0 +1,55 @@
|
||||
class TopicsController < ApplicationController
|
||||
include CommentableActions
|
||||
include FlagActions
|
||||
|
||||
before_action :load_community
|
||||
before_action :load_topic, only: [:show, :edit, :update]
|
||||
|
||||
has_orders %w{most_voted newest oldest}, only: :show
|
||||
|
||||
skip_authorization_check
|
||||
|
||||
def new
|
||||
@topic = Topic.new
|
||||
end
|
||||
|
||||
def create
|
||||
@topic = Topic.new(topic_params.merge(author: current_user, community_id: params[:community_id]))
|
||||
if @topic.save
|
||||
redirect_to community_path(@community), notice: I18n.t('flash.actions.create.topic')
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@commentable = @topic
|
||||
@comment_tree = CommentTree.new(@commentable, params[:page], @current_order)
|
||||
set_comment_flags(@comment_tree.comments)
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if @topic.update(topic_params)
|
||||
redirect_to community_path(@community), notice: t('flash.actions.update.topic')
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def topic_params
|
||||
params.require(:topic).permit(:title, :description)
|
||||
end
|
||||
|
||||
def load_community
|
||||
@community = Community.find(params[:community_id])
|
||||
end
|
||||
|
||||
def load_topic
|
||||
@topic = Topic.find(params[:id])
|
||||
end
|
||||
end
|
||||
@@ -42,7 +42,7 @@ module CommentsHelper
|
||||
|
||||
def commentable_path(comment)
|
||||
commentable = comment.commentable
|
||||
|
||||
|
||||
case comment.commentable_type
|
||||
when "Budget::Investment"
|
||||
budget_investment_path(commentable.budget_id, commentable)
|
||||
@@ -50,6 +50,8 @@ module CommentsHelper
|
||||
legislation_process_question_path(commentable.process, commentable)
|
||||
when "Legislation::Annotation"
|
||||
legislation_process_draft_version_annotation_path(commentable.draft_version.process, commentable.draft_version, commentable)
|
||||
when "Topic"
|
||||
community_topic_path(comment.commentable.community, comment.commentable)
|
||||
else
|
||||
commentable
|
||||
end
|
||||
|
||||
42
app/helpers/communities_helper.rb
Normal file
@@ -0,0 +1,42 @@
|
||||
module CommunitiesHelper
|
||||
|
||||
def community_title(community)
|
||||
if community.from_proposal?
|
||||
community.proposal.title
|
||||
else
|
||||
investment = Budget::Investment.where(community_id: community.id).first
|
||||
investment.title
|
||||
end
|
||||
end
|
||||
|
||||
def community_text(community)
|
||||
community.from_proposal? ? t("community.show.title.proposal") : t("community.show.title.investment")
|
||||
end
|
||||
|
||||
def community_description(community)
|
||||
community.from_proposal? ? t("community.show.description.proposal") : t("community.show.description.investment")
|
||||
end
|
||||
|
||||
def is_author?(community, participant)
|
||||
if community.from_proposal?
|
||||
community.proposal.author_id == participant.id
|
||||
else
|
||||
investment = Budget::Investment.where(community_id: community.id).first
|
||||
investment.author_id == participant.id
|
||||
end
|
||||
end
|
||||
|
||||
def community_back_link_path(community)
|
||||
if community.from_proposal?
|
||||
proposal_path(community.proposal)
|
||||
else
|
||||
investment = Budget::Investment.where(community_id: community.id).first
|
||||
budget_investment_path(investment.budget_id, investment)
|
||||
end
|
||||
end
|
||||
|
||||
def community_access_text(community)
|
||||
community.from_proposal? ? t("community.sidebar.description.proposal") : t("community.sidebar.description.investment")
|
||||
end
|
||||
|
||||
end
|
||||
23
app/helpers/shifts_helper.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
module ShiftsHelper
|
||||
|
||||
def shift_dates_select_options(polls)
|
||||
options = []
|
||||
(start_date(polls)..end_date(polls)).each do |date|
|
||||
options << [l(date, format: :long), l(date)]
|
||||
end
|
||||
options_for_select(options, params[:date])
|
||||
end
|
||||
|
||||
def start_date(polls)
|
||||
polls.map(&:starts_at).min.to_date
|
||||
end
|
||||
|
||||
def end_date(polls)
|
||||
polls.map(&:ends_at).max.to_date
|
||||
end
|
||||
|
||||
def officer_select_options(officers)
|
||||
officers.collect { |officer| [officer.name, officer.id] }
|
||||
end
|
||||
|
||||
end
|
||||
11
app/helpers/topics_helper.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
module TopicsHelper
|
||||
|
||||
def disabled_create_topic
|
||||
"disabled" unless current_user
|
||||
end
|
||||
|
||||
def disabled_info_title
|
||||
t("community.show.sidebar.disabled_info_title") unless current_user
|
||||
end
|
||||
|
||||
end
|
||||
@@ -33,7 +33,7 @@ module Abilities
|
||||
can :unmark_featured, Debate
|
||||
|
||||
can :comment_as_administrator, [Debate, Comment, Proposal, Poll::Question, Budget::Investment,
|
||||
Legislation::Question, Legislation::Annotation]
|
||||
Legislation::Question, Legislation::Annotation, Topic]
|
||||
|
||||
can [:search, :create, :index, :destroy], ::Administrator
|
||||
can [:search, :create, :index, :destroy], ::Moderator
|
||||
|
||||
@@ -6,7 +6,7 @@ module Abilities
|
||||
merge Abilities::Moderation.new(user)
|
||||
|
||||
can :comment_as_moderator, [Debate, Comment, Proposal, Budget::Investment, Poll::Question,
|
||||
Legislation::Question, Legislation::Annotation]
|
||||
Legislation::Question, Legislation::Annotation, Topic]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,6 +6,7 @@ class Budget
|
||||
include Searchable
|
||||
include Reclassification
|
||||
include Followable
|
||||
include Communitable
|
||||
include Documentable
|
||||
documentable max_documents_allowed: 3,
|
||||
max_file_size: 3.megabytes,
|
||||
|
||||
@@ -3,7 +3,7 @@ class Comment < ActiveRecord::Base
|
||||
include HasPublicAuthor
|
||||
include Graphqlable
|
||||
|
||||
COMMENTABLE_TYPES = %w(Debate Proposal Budget::Investment Poll::Question Legislation::Question Legislation::Annotation).freeze
|
||||
COMMENTABLE_TYPES = %w(Debate Proposal Budget::Investment Poll::Question Legislation::Question Legislation::Annotation Topic).freeze
|
||||
|
||||
acts_as_paranoid column: :hidden_at
|
||||
include ActsAsParanoidAliases
|
||||
|
||||
39
app/models/community.rb
Normal file
@@ -0,0 +1,39 @@
|
||||
class Community < ActiveRecord::Base
|
||||
has_one :proposal
|
||||
has_one :investment
|
||||
has_many :topics
|
||||
|
||||
def participants
|
||||
users_participants = users_who_commented_by +
|
||||
users_who_topics_author_by +
|
||||
author_from_community
|
||||
users_participants.uniq
|
||||
end
|
||||
|
||||
def from_proposal?
|
||||
self.proposal.present?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def users_who_commented_by
|
||||
topics_ids = topics.pluck(:id)
|
||||
query = "comments.commentable_id IN (?)and comments.commentable_type = 'Topic'"
|
||||
User.by_comments(query, topics_ids)
|
||||
end
|
||||
|
||||
def users_who_topics_author_by
|
||||
author_ids = topics.pluck(:author_id)
|
||||
User.by_authors(author_ids)
|
||||
end
|
||||
|
||||
def author_from_community
|
||||
if from_proposal?
|
||||
User.where(id: proposal.author_id)
|
||||
else
|
||||
investment = Budget::Investment.where(community_id: id).first
|
||||
User.where(id: investment.author_id)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
14
app/models/concerns/communitable.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
module Communitable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
belongs_to :community
|
||||
before_create :associate_community
|
||||
end
|
||||
|
||||
def associate_community
|
||||
community = Community.create
|
||||
self.community_id = community.id
|
||||
end
|
||||
|
||||
end
|
||||
@@ -35,6 +35,10 @@ class Poll < ActiveRecord::Base
|
||||
ends_at < timestamp
|
||||
end
|
||||
|
||||
def self.current_or_incoming
|
||||
current + incoming
|
||||
end
|
||||
|
||||
def answerable_by?(user)
|
||||
user.present? &&
|
||||
user.level_two_or_three_verified? &&
|
||||
|
||||
@@ -2,6 +2,7 @@ class Poll
|
||||
class Booth < ActiveRecord::Base
|
||||
has_many :booth_assignments, class_name: "Poll::BoothAssignment"
|
||||
has_many :polls, through: :booth_assignments
|
||||
has_many :shifts
|
||||
|
||||
validates :name, presence: true, uniqueness: true
|
||||
|
||||
|
||||
22
app/models/poll/shift.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
class Poll
|
||||
class Shift < ActiveRecord::Base
|
||||
belongs_to :booth
|
||||
belongs_to :officer
|
||||
|
||||
validates :booth_id, presence: true
|
||||
validates :officer_id, presence: true
|
||||
validates :date, presence: true
|
||||
validates :date, uniqueness: { scope: [:officer_id, :booth_id] }
|
||||
|
||||
after_create :create_officer_assignments
|
||||
|
||||
def create_officer_assignments
|
||||
booth.booth_assignments.each do |booth_assignment|
|
||||
attrs = { officer_id: officer_id,
|
||||
date: date,
|
||||
booth_assignment_id: booth_assignment.id }
|
||||
Poll::OfficerAssignment.create!(attrs)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -9,6 +9,7 @@ class Proposal < ActiveRecord::Base
|
||||
include HasPublicAuthor
|
||||
include Graphqlable
|
||||
include Followable
|
||||
include Communitable
|
||||
include Documentable
|
||||
documentable max_documents_allowed: 3,
|
||||
max_file_size: 3.megabytes,
|
||||
|
||||
20
app/models/topic.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
class Topic < ActiveRecord::Base
|
||||
include Flaggable
|
||||
|
||||
acts_as_paranoid column: :hidden_at
|
||||
include ActsAsParanoidAliases
|
||||
|
||||
belongs_to :community
|
||||
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
|
||||
|
||||
has_many :comments, as: :commentable
|
||||
|
||||
validates :title, presence: true
|
||||
validates :description, presence: true
|
||||
validates :author, presence: true
|
||||
|
||||
scope :sort_by_newest, -> { order(created_at: :desc) }
|
||||
scope :sort_by_oldest, -> { order(created_at: :asc) }
|
||||
scope :sort_by_most_commented, -> { reorder(comments_count: :desc) }
|
||||
|
||||
end
|
||||
@@ -57,11 +57,13 @@ class User < ActiveRecord::Base
|
||||
scope :officials, -> { where("official_level > 0") }
|
||||
scope :newsletter, -> { where(newsletter: true) }
|
||||
scope :for_render, -> { includes(:organization) }
|
||||
scope :by_document, ->(document_type, document_number) { where(document_type: document_type, document_number: document_number) }
|
||||
scope :by_document, -> (document_type, document_number) { where(document_type: document_type, document_number: document_number) }
|
||||
scope :email_digest, -> { where(email_digest: true) }
|
||||
scope :active, -> { where(erased_at: nil) }
|
||||
scope :erased, -> { where.not(erased_at: nil) }
|
||||
scope :public_for_api, -> { all }
|
||||
scope :by_comments, -> (query, topics_ids) { joins(:comments).where(query, topics_ids).uniq }
|
||||
scope :by_authors, -> (author_ids) { where("users.id IN (?)", author_ids) }
|
||||
|
||||
before_validation :clean_document_number
|
||||
|
||||
|
||||
@@ -73,9 +73,13 @@
|
||||
<%= link_to t('admin.menu.poll_officers'), admin_officers_path %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "booths" %>>
|
||||
<li <%# "class=active" if controller_name == "booths" %>>
|
||||
<%= link_to t('admin.menu.poll_booths'), admin_booths_path %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "booths" %>>
|
||||
<%= link_to t('admin.menu.poll_shifts'), admin_booths_path %>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
@@ -41,4 +41,3 @@
|
||||
<div id="investments">
|
||||
<%= render '/admin/budget_investments/investments' %>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -41,4 +41,4 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= paginate @budgets %>
|
||||
<%= paginate @budgets %>
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
<%= booth.location %>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<%= link_to t("admin.booths.booth.shifts"),
|
||||
new_admin_booth_shift_path(booth),
|
||||
class: "button hollow" %>
|
||||
<%= link_to t("admin.actions.edit"),
|
||||
edit_admin_booth_path(booth),
|
||||
class: "button hollow" %>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<th><%= t("admin.booths.index.name") %></th>
|
||||
<th><%= t("admin.booths.index.location") %></th>
|
||||
<th> </th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @booths.each do |booth| %>
|
||||
|
||||
@@ -5,35 +5,6 @@
|
||||
|
||||
<h2><%= @officer.name %> - <%= @officer.email %></h2>
|
||||
|
||||
<%= form_tag(admin_poll_officer_assignments_path(@poll), {id: "officer_assignment_form"}) do %>
|
||||
<fieldset class="fieldset">
|
||||
<legend><%= t("admin.poll_officer_assignments.by_officer.new_assignment") %></legend>
|
||||
<div class="small-12 medium-4 column">
|
||||
<label><%= t("admin.poll_officer_assignments.by_officer.date") %></label>
|
||||
<%= select_tag :date,
|
||||
poll_dates_select_options(@poll) + poll_final_recount_option(@poll),
|
||||
{ prompt: t("admin.poll_officer_assignments.by_officer.select_date"),
|
||||
label: false } %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-4 column">
|
||||
<label><%= t("admin.poll_officer_assignments.by_officer.booth") %></label>
|
||||
<%= select_tag :booth_id,
|
||||
poll_booths_select_options(@poll),
|
||||
{ prompt: t("admin.poll_officer_assignments.by_officer.select_booth"),
|
||||
label: false } %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-4 column">
|
||||
<%= hidden_field_tag :officer_id, @officer.id %>
|
||||
<%= hidden_field_tag :poll_id, @poll.id %>
|
||||
<%= submit_tag t("admin.poll_officer_assignments.by_officer.add_assignment"),
|
||||
class: "button expanded hollow margin-top" %>
|
||||
</div>
|
||||
</fieldset>
|
||||
<% end %>
|
||||
|
||||
|
||||
<% if @officer_assignments.empty? %>
|
||||
<div class="callout primary margin-top">
|
||||
<%= t("admin.poll_officer_assignments.by_officer.no_assignments") %>
|
||||
@@ -45,7 +16,6 @@
|
||||
<tr>
|
||||
<th><%= t("admin.poll_officer_assignments.by_officer.date") %></th>
|
||||
<th><%= t("admin.poll_officer_assignments.by_officer.booth") %></th>
|
||||
<th class="text-right"><%= t("admin.poll_officer_assignments.by_officer.assignment") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -53,12 +23,6 @@
|
||||
<tr id="<%= dom_id officer_assignment %>">
|
||||
<td><%= officer_assignment.final? ? t('polls.final_date') : l(officer_assignment.date.to_date) %></td>
|
||||
<td><%= booth_name_with_location(officer_assignment.booth_assignment.booth) %></td>
|
||||
<td class="text-right">
|
||||
<%= link_to t("admin.poll_officer_assignments.by_officer.remove_assignment"),
|
||||
admin_poll_officer_assignment_path(@poll, officer_assignment),
|
||||
method: :delete,
|
||||
class: "button hollow alert" %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
@@ -93,6 +57,3 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
||||
|
||||
24
app/views/admin/poll/shifts/_shifts.html.erb
Normal file
@@ -0,0 +1,24 @@
|
||||
<h3><%= t("admin.poll_shifts.new.assignments") %></h3>
|
||||
<table class="fixed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.poll_shifts.new.date") %></th>
|
||||
<th><%= t("admin.poll_shifts.new.officer") %></th>
|
||||
<th class="text-right"><%= t("admin.poll_shifts.new.assignment") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @shifts.each do |shift| %>
|
||||
<tr id="shift_<%= shift.id %>" class="shift">
|
||||
<td><%= l(shift.date.to_date, format: :long) %></td>
|
||||
<td><%= shift.officer.name %></td>
|
||||
<td class="text-right">
|
||||
<%= link_to t("admin.poll_shifts.new.remove_assignment"),
|
||||
admin_booth_shift_path(@booth, shift),
|
||||
method: :delete,
|
||||
class: "button hollow alert" %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
46
app/views/admin/poll/shifts/new.html.erb
Normal file
@@ -0,0 +1,46 @@
|
||||
<%= back_link_to admin_booths_path %>
|
||||
|
||||
<h2><%= @booth.name %></h2>
|
||||
|
||||
<%= form_for @shift, as: :shift, url: admin_booth_shifts_path do |f| %>
|
||||
<%= render "shared/errors", resource: @shift %>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend>
|
||||
<%= t("admin.poll_shifts.new.new_assignment") %>
|
||||
</legend>
|
||||
|
||||
<div class="small-12 medium-4 column">
|
||||
<label><%= t("admin.poll_shifts.new.date") %></label>
|
||||
<%= f.select :date,
|
||||
shift_dates_select_options(@polls),
|
||||
prompt: t("admin.poll_shifts.new.select_date"),
|
||||
label: false %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-4 column">
|
||||
<label><%= t("admin.poll_shifts.new.officer") %></label>
|
||||
<%= f.select :officer_id,
|
||||
officer_select_options(@officers),
|
||||
prompt: t("admin.poll_shifts.new.select_officer"),
|
||||
label: false %>
|
||||
</div>
|
||||
|
||||
<%= f.hidden_field :booth_id, value: @booth.id %>
|
||||
|
||||
<div class="small-12 medium-4 column">
|
||||
<%= f.submit t("admin.poll_shifts.new.add_assignment"),
|
||||
class: "button expanded hollow margin-top" %>
|
||||
</div>
|
||||
</fieldset>
|
||||
<% end %>
|
||||
|
||||
<div id="shifts">
|
||||
<% if @shifts.empty? %>
|
||||
<div class="callout primary margin-top">
|
||||
<%= t("admin.poll_shifts.new.no_assignments") %>
|
||||
</div>
|
||||
<% else %>
|
||||
<%= render "shifts" %>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -123,6 +123,8 @@
|
||||
<%= render 'follows/follow_button', follow: find_or_build_follow(current_user, investment) %>
|
||||
<% end %>
|
||||
|
||||
<%= render 'communities/access_button', community: investment.community %>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
<%= render @comment %>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
8
app/views/communities/_access_button.html.erb
Normal file
@@ -0,0 +1,8 @@
|
||||
<% if feature?("community") %>
|
||||
<div class="sidebar-divider"></div>
|
||||
<h2><%= t("community.sidebar.title") %></h2>
|
||||
<p>
|
||||
<%= community_access_text(community) %>
|
||||
</p>
|
||||
<%= link_to t("community.sidebar.button_to_access"), community_path(community.id), class: 'button hollow expanded' %>
|
||||
<% end %>
|
||||
41
app/views/communities/_participants.html.erb
Normal file
@@ -0,0 +1,41 @@
|
||||
<div class="row column communities-participant">
|
||||
|
||||
<ul class="tabs" data-tabs id="communities-show-tabs">
|
||||
|
||||
<li class="tabs-title is-active">
|
||||
<%= link_to "#tab-participants" do %>
|
||||
<h3>
|
||||
<%= t("community.show.tab.participants") %>
|
||||
<span class="js-comments-count">(<%= @participants.count %>)</span>
|
||||
</h3>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<% @participants.each do |participant| %>
|
||||
<div class="comment-body">
|
||||
<div class="comment-info">
|
||||
|
||||
<%= avatar_image( participant, seed: participant.id, size: 32, class: 'author-photo') %>
|
||||
|
||||
<div class="comment-info">
|
||||
|
||||
<span class="user-name">
|
||||
<%= link_to participant.name, user_path(participant)%>
|
||||
</span>
|
||||
|
||||
<% if is_author?(@community, participant) %>
|
||||
•
|
||||
<span class="label round is-author">
|
||||
<%= t("comments.comment.author") %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
39
app/views/communities/show.html.erb
Normal file
@@ -0,0 +1,39 @@
|
||||
<div class="communities-show">
|
||||
|
||||
<div class="jumbo light">
|
||||
<div class="row">
|
||||
<div class="small-12 column">
|
||||
<%= back_link_to community_back_link_path(@community) %>
|
||||
<h2><%= community_text(@community) %></h2>
|
||||
<p class="lead"> <%= community_title(@community) %> </p>
|
||||
<p><%= community_description(@community) %> </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<aside class="show-for-small-only small-12 column">
|
||||
<div class="sidebar-divider"></div>
|
||||
<h2><%= t("community.show.sidebar.participate") %></h2>
|
||||
<%= link_to t("community.show.sidebar.new_topic"), new_community_topic_path(@community.id), class: "button expanded #{disabled_create_topic}" %>
|
||||
</aside>
|
||||
|
||||
<div class="small-12 medium-9 column">
|
||||
<div id="topics" class="topics-list">
|
||||
<%= render "topics/topics", topics: @topics %>
|
||||
</div>
|
||||
<%= paginate @topics %>
|
||||
</div>
|
||||
|
||||
<aside class="small-12 medium-3 hide-for-small-only column">
|
||||
<div class="sidebar-divider"></div>
|
||||
<h2><%= t("community.show.sidebar.participate") %></h2>
|
||||
<%= link_to t("community.show.sidebar.new_topic"), new_community_topic_path(@community.id), class: "button expanded #{disabled_create_topic}", title: "#{disabled_info_title}" %>
|
||||
</aside>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<%= render 'participants' %>
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<%= render 'legislation/processes/header', process: @process, header: :small %>
|
||||
|
||||
<%= render 'legislation/processes/key_dates', process: @process, phase: :allegations %>
|
||||
<%= render 'legislation/processes/key_dates', process: @process, phase: :allegations_phase %>
|
||||
|
||||
<div class="column row">
|
||||
<div class="draft-panels small-12 column row">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<%= render 'legislation/processes/header', process: @process, header: :small %>
|
||||
|
||||
<%= render 'legislation/processes/key_dates', process: @process, phase: :allegations %>
|
||||
<%= render 'legislation/processes/key_dates', process: @process, phase: :allegations_phase %>
|
||||
|
||||
<div class="column row">
|
||||
<div class="draft-panels small-12 column row">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<%= render 'legislation/processes/header', process: @process, header: :small %>
|
||||
|
||||
<%= render 'legislation/processes/key_dates', process: @process, phase: :allegations %>
|
||||
<%= render 'legislation/processes/key_dates', process: @process, phase: :allegations_phase %>
|
||||
|
||||
<div class="column row">
|
||||
<div class="draft-panels small-12 column row">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<%= render 'legislation/processes/header', process: @process, header: :small %>
|
||||
|
||||
<%= render 'legislation/processes/key_dates', process: @process, phase: :allegations %>
|
||||
<%= render 'legislation/processes/key_dates', process: @process, phase: :allegations_phase %>
|
||||
|
||||
<div class="column row">
|
||||
<div class="draft-panels small-12 column row">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<% if header == :small %>
|
||||
<div class="legislation-hero legislation-allegation no-margin-top grey-heading" data-target="legislation-header-small">
|
||||
<div class="legislation-hero jumbo grey-heading" data-target="legislation-header-small">
|
||||
<div class="row headline">
|
||||
<div class="small-12 medium-8 column">
|
||||
<h3 class="headline-small"><%= process.title %></h3>
|
||||
@@ -9,21 +9,19 @@
|
||||
<div id="debate-show" class="row description legislation-debate-show">
|
||||
<div class="small-12 column">
|
||||
<% if process.description.present? %>
|
||||
<h4><%= t('legislation.processes.header_full.description') %></h4>
|
||||
<p class="title"><%= t('legislation.processes.header_full.description') %></p>
|
||||
<%= markdown process.description %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% if process.additional_info.present? %>
|
||||
<div class="small-12 column debate-add-info">
|
||||
<div class="debate-info-wrapper">
|
||||
<%= markdown process.additional_info if process.additional_info %>
|
||||
</div>
|
||||
<%= markdown process.additional_info if process.additional_info %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if process.description.present? || process.additional_info.present? %>
|
||||
<div class="text-center half-gradient">
|
||||
<div class="text-center">
|
||||
<a class="button big text-center button-circle" title="<%= t('.view_process_information') %>" id="js-toggle-small-debate">
|
||||
<span class="icon-angle-down" aria-hidden="true"></span>
|
||||
</a>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="legislation-hero no-margin-top grey-heading" style="display:<%= hidden ? 'none' : 'block' %>" data-target="legislation-header-full">
|
||||
<div class="legislation-hero jumbo grey-heading" style="display:<%= hidden ? 'none' : 'block' %>" data-target="legislation-header-full">
|
||||
<div class="row headline">
|
||||
<div class="small-12 medium-8 column">
|
||||
<p><%= t('.title') %></p>
|
||||
<%= back_link_to legislation_processes_path %>
|
||||
<h2>
|
||||
<%= process.title %>
|
||||
</h2>
|
||||
@@ -11,21 +11,19 @@
|
||||
<div class="row description">
|
||||
<div class="small-12 column">
|
||||
<% if process.description.present? %>
|
||||
<h4><%= t('.description') %></h4>
|
||||
<p class="title"><%= t('.description') %></p>
|
||||
<%= markdown process.description %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% if process.additional_info.present? %>
|
||||
<div id="debate-show" class="small-12 column debate-add-info legislation-debate-show">
|
||||
<div class="debate-info-wrapper">
|
||||
<%= markdown process.additional_info if process.additional_info %>
|
||||
</div>
|
||||
<%= markdown process.additional_info if process.additional_info %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if process.additional_info.present? %>
|
||||
<div class="text-center half-gradient">
|
||||
<div class="text-center">
|
||||
<a id="js-toggle-debate" class="button big text-center" title="<%= t('.more_info') %>">
|
||||
<strong><%= t('.more_info') %></strong>
|
||||
</a>
|
||||
|
||||
@@ -3,45 +3,45 @@
|
||||
<div class="row">
|
||||
<div class="small-12 column">
|
||||
<h3><%= t("legislation.processes.shared.key_dates") %></h3>
|
||||
|
||||
<ul>
|
||||
<% if process.debate_phase.enabled? %>
|
||||
<li <%= 'class="active"' if phase.to_sym == :debate_phase %>>
|
||||
<%= link_to debate_legislation_process_path(process) do %>
|
||||
<h4><%= t('legislation.processes.shared.debate_dates') %></h4>
|
||||
<p><%= format_date(process.debate_start_date) %> - <%= format_date(process.debate_end_date) %></p>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if process.draft_publication.enabled? %>
|
||||
<li <%= 'class="active"' if phase.to_sym == :draft_publication %>>
|
||||
<%= link_to draft_publication_legislation_process_path(process) do %>
|
||||
<h4><%= t('legislation.processes.shared.draft_publication_date') %></h4>
|
||||
<p><%= format_date(process.draft_publication_date) %></p>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if process.allegations_phase.enabled? %>
|
||||
<li <%= 'class="active"' if phase.to_sym == :allegations_phase %>>
|
||||
<%= link_to allegations_legislation_process_path(process) do %>
|
||||
<h4><%= t('legislation.processes.shared.allegations_dates') %></h4>
|
||||
<p><%= format_date(process.allegations_start_date) %> - <%= format_date(process.allegations_end_date) %></p>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if process.result_publication.enabled? %>
|
||||
<li <%= 'class="active"' if phase.to_sym == :result_publication %>>
|
||||
<%= link_to result_publication_legislation_process_path(process) do %>
|
||||
<h4><%= t('legislation.processes.shared.result_publication_date') %></h4>
|
||||
<p><%= format_date(process.result_publication_date) %></p>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
<% if process.debate_phase.enabled? %>
|
||||
<li <%= "class=active" if phase == :debate_phase %>>
|
||||
<%= link_to debate_legislation_process_path(process) do %>
|
||||
<h4><%= t('legislation.processes.shared.debate_dates') %></h4>
|
||||
<p><%= format_date(process.debate_start_date) %> - <%= format_date(process.debate_end_date) %></p>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if process.draft_publication.enabled? %>
|
||||
<li <%= "class=active" if phase == :draft_publication %>>
|
||||
<%= link_to draft_publication_legislation_process_path(process) do %>
|
||||
<h4><%= t('legislation.processes.shared.draft_publication_date') %></h4>
|
||||
<p><%= format_date(process.draft_publication_date) %></p>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if process.allegations_phase.enabled? %>
|
||||
<li <%= "class=active" if phase == :allegations_phase %>>
|
||||
<%= link_to allegations_legislation_process_path(process) do %>
|
||||
<h4><%= t('legislation.processes.shared.allegations_dates') %></h4>
|
||||
<p><%= format_date(process.allegations_start_date) %> - <%= format_date(process.allegations_end_date) %></p>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if process.result_publication.enabled? %>
|
||||
<li <%= "class=active" if phase == :result_publication %>>
|
||||
<%= link_to result_publication_legislation_process_path(process) do %>
|
||||
<h4><%= t('legislation.processes.shared.result_publication_date') %></h4>
|
||||
<p><%= format_date(process.result_publication_date) %></p>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -93,12 +93,12 @@
|
||||
<aside class="margin-bottom">
|
||||
<%= link_to t("proposals.index.start_proposal"), new_proposal_path, class: 'button expanded' %>
|
||||
<% if params[:retired].blank? %>
|
||||
<%= render 'categories' %>
|
||||
<%= render "shared/tag_cloud", taggable: 'proposal' %>
|
||||
<%= render 'geozones' %>
|
||||
<%= render 'popular' %>
|
||||
<% end %>
|
||||
<%= render 'retired' %>
|
||||
<%= render 'categories' %>
|
||||
<%= render "shared/tag_cloud", taggable: 'proposal' %>
|
||||
<%= render 'geozones' %>
|
||||
<%= render 'popular' %>
|
||||
<% end %>
|
||||
<%= render 'retired' %>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -159,6 +159,8 @@
|
||||
<%= render 'follows/follow_button', follow: find_or_build_follow(current_user, @proposal) %>
|
||||
<% end %>
|
||||
|
||||
<%= render 'communities/access_button', community: @proposal.community %>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<div class="highlight jumbo">
|
||||
<div class="highlight jumbo help-header">
|
||||
<div class="row">
|
||||
<div class="small-12 medium-9 column" data-magellan>
|
||||
<%= image_tag "help/help_icon_#{image}.png", alt: t("#{i18n_namespace}.icon_alt"), class: "align-top" %>
|
||||
<h1 class="inline-block"><%= t("#{i18n_namespace}.title") %></h1>
|
||||
<p class="lead"><%= t("#{i18n_namespace}.description") %></p>
|
||||
<%= link_to t("#{i18n_namespace}.help"), "#section_help", class: "help-link" %>
|
||||
<p>
|
||||
<%= t("#{i18n_namespace}.description") %><br>
|
||||
<%= link_to t("#{i18n_namespace}.help"), "#section_help" %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
<div class="wide-order-selector small-12 medium-8">
|
||||
<form>
|
||||
<div class="small-12 medium-8 float-left">
|
||||
<div class="small-12 medium-6 float-left">
|
||||
<label for="order-selector-participation">
|
||||
<%= t("#{i18n_namespace}.select_order") %>
|
||||
</label>
|
||||
</div>
|
||||
<div class="small-12 medium-4 float-left">
|
||||
<div class="small-12 medium-6 float-left">
|
||||
<select class="js-location-changer js-order-selector select-order" data-order="<%= @current_order %>" name="order-selector" id="order-selector-participation">
|
||||
<% @valid_orders.each do |order| %>
|
||||
<option <%= 'selected' if order == @current_order %>
|
||||
|
||||
26
app/views/topics/_comments.html.erb
Normal file
@@ -0,0 +1,26 @@
|
||||
<% cache [locale_and_user_status, @current_order, commentable_cache_key(@topic), @comment_tree.comments, @comment_tree.comment_authors, @topic.comments_count, @comment_flags] do %>
|
||||
<div class="row comments">
|
||||
|
||||
<div id="comments" class="small-12 column">
|
||||
<%= render 'shared/wide_order_selector', i18n_namespace: "comments" %>
|
||||
|
||||
<% @comment_tree.root_comments.each do |comment| %>
|
||||
<%= render 'comments/comment', comment: comment %>
|
||||
<% end %>
|
||||
|
||||
<%= paginate @comment_tree.root_comments %>
|
||||
|
||||
<% if user_signed_in? %>
|
||||
<%= render 'comments/form', {commentable: @topic, parent_id: nil, toggeable: false} %>
|
||||
<% else %>
|
||||
<br>
|
||||
<div data-alert class="callout primary">
|
||||
<%= t("topics.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 %>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
18
app/views/topics/_filter_subnav.html.erb
Normal file
@@ -0,0 +1,18 @@
|
||||
<div class="row">
|
||||
<div class="small-12 column">
|
||||
|
||||
<ul class="tabs" data-tabs id="topics-tabs">
|
||||
|
||||
<li class="tabs-title is-active">
|
||||
<%= link_to "#tab-comments" do %>
|
||||
<h3>
|
||||
<%= t("community.topic.show.tab.comments_tab") %>
|
||||
<span class="js-comments-count">(<%= @topic.comments_count %>)</span>
|
||||
</h3>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
21
app/views/topics/_form.html.erb
Normal file
@@ -0,0 +1,21 @@
|
||||
<%= form_for([@community, @topic]) do |f| %>
|
||||
|
||||
<%= render 'shared/errors', resource: @topic %>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="small-12 column">
|
||||
<%= f.label :title, t("community.topic.form.topic_title") %>
|
||||
<%= f.text_field :title, label: false %>
|
||||
</div>
|
||||
<div class="small-12 column">
|
||||
<%= f.label :description, t("community.topic.form.topic_description") %>
|
||||
<%= f.text_area :description, label: false %>
|
||||
</div>
|
||||
<div class="actions small-12 column">
|
||||
<%= f.submit(class: "button", value: t("community.topic.form.#{action_name}.submit_button")) %>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<% end %>
|
||||
13
app/views/topics/_recommendations.html.erb
Normal file
@@ -0,0 +1,13 @@
|
||||
<div class="small-12 medium-3 column">
|
||||
|
||||
<span class="icon-proposals float-right"></span>
|
||||
|
||||
<h2><%= t("community.topic.sidebar.recommendations_title") %></h2>
|
||||
|
||||
<ul class="recommendations">
|
||||
<li><%= t("community.topic.sidebar.recommendation_one") %></li>
|
||||
<li><%= t("community.topic.sidebar.recommendation_two") %></li>
|
||||
<li><%= t("community.topic.sidebar.recommendation_three") %></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
48
app/views/topics/_topics.html.erb
Normal file
@@ -0,0 +1,48 @@
|
||||
<% if topics.any? %>
|
||||
|
||||
<div class="row column">
|
||||
<div class="order">
|
||||
<%= render 'shared/wide_order_selector', i18n_namespace: "comments" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% topics.each do |topic| %>
|
||||
|
||||
<div id="<%= dom_id(topic) %>" class="panel column">
|
||||
<div class="small-10 column">
|
||||
|
||||
<h3><%= link_to topic.title, community_topic_path(@community, topic) %></h3>
|
||||
|
||||
<p class="topic-info">
|
||||
<span class="icon-comments"></span>
|
||||
<%= link_to t("community.show.topic.comments", count: topic.comments_count), community_topic_path(@community, topic, anchor: "comments") %>
|
||||
<span class="bullet"> • </span>
|
||||
<%= I18n.l topic.created_at.to_date %>
|
||||
<span class="bullet"> • </span>
|
||||
<%= topic.author.name %>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="small-2 column text-right">
|
||||
<% if topic.author == current_user %>
|
||||
<%= link_to t("community.show.topic.edit_button"), edit_community_topic_path(@community.id, topic), class: 'button small hollow' %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<% end %>
|
||||
|
||||
<% else %>
|
||||
<h3><%= t("community.show.create_first_community_topic.first_theme") %></h3>
|
||||
<% if user_signed_in? %>
|
||||
<%= t("community.show.create_first_community_topic.first_theme_not_logged_in") %>
|
||||
<% else %>
|
||||
<div class="callout primary">
|
||||
<%= t("community.show.create_first_community_topic.sub_first_theme",
|
||||
link: link_to(t("community.show.create_first_community_topic.sign_link",
|
||||
org_name: setting['org_name']), new_user_session_path)).html_safe %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
11
app/views/topics/edit.html.erb
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="topic-form row">
|
||||
|
||||
<div class="small-12 medium-9 column">
|
||||
<%= back_link_to community_path(@community) %>
|
||||
<h1><%= t("community.topic.edit") %></h1>
|
||||
<%= render "form" %>
|
||||
</div>
|
||||
|
||||
<%= render "recommendations" %>
|
||||
|
||||
</div>
|
||||
11
app/views/topics/new.html.erb
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="topic-new row">
|
||||
|
||||
<div class="small-12 medium-9 column">
|
||||
<%= back_link_to community_path(@community) %>
|
||||
<h1><%= t("community.topic.create") %></h1>
|
||||
<%= render 'form' %>
|
||||
</div>
|
||||
|
||||
<%= render "recommendations" %>
|
||||
|
||||
</div>
|
||||
27
app/views/topics/show.html.erb
Normal file
@@ -0,0 +1,27 @@
|
||||
<div class="row topic-show">
|
||||
<div class="small-12 medium-12 column">
|
||||
|
||||
<%= back_link_to community_path(@community) %>
|
||||
<br>
|
||||
|
||||
<p><%= community_text(@community) %> <strong><%= community_title(@community) %></strong></p>
|
||||
<h1><%= @topic.title %></h1>
|
||||
<div class="topic-info">
|
||||
<p><%= @topic.description %></p>
|
||||
<%= render '/shared/author_info', resource: @topic %>
|
||||
|
||||
<span class="bullet"> • </span>
|
||||
<%= l @topic.created_at.to_date %>
|
||||
<span class="bullet"> • </span>
|
||||
<span class="icon-comments"></span>
|
||||
</div>
|
||||
|
||||
<div class="tabs-content" data-tabs-content="topics-tabs" role="tablist">
|
||||
<%= render "topics/filter_subnav" %>
|
||||
<div class="tabs-panel is-active" id="tab-comments">
|
||||
<%= render "topics/comments" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -37,6 +37,7 @@ data:
|
||||
- config/locales/%{locale}/officing.yml
|
||||
- config/locales/%{locale}/budgets.yml
|
||||
- config/locales/%{locale}/legislation.yml
|
||||
- config/locales/%{locale}/community.yml
|
||||
- config/locales/%{locale}/documents.yml
|
||||
|
||||
# Locale files to write new keys to, based on a list of key pattern => file rules. Matched from top to bottom:
|
||||
|
||||
@@ -403,6 +403,7 @@ en:
|
||||
poll_officers: Poll officers
|
||||
polls: Polls
|
||||
poll_booths: Booths location
|
||||
poll_shifts: Manage shifts
|
||||
officials: Officials
|
||||
organizations: Organisations
|
||||
settings: Configuration settings
|
||||
@@ -481,11 +482,6 @@ en:
|
||||
search: Search
|
||||
user_not_found: User not found
|
||||
poll_officer_assignments:
|
||||
flash:
|
||||
destroy: "Officing shift removed"
|
||||
create: "Officing shift added"
|
||||
error_destroy: "An error ocurred when removing officer assignment"
|
||||
error_create: "An error ocurred when adding officer assignment"
|
||||
index:
|
||||
officers_title: "List of officers"
|
||||
no_officers: "There are no officers assigned to this poll."
|
||||
@@ -494,18 +490,27 @@ en:
|
||||
add_officer_assignments: "Add shifts as officer"
|
||||
edit_officer_assignments: "Edit officing shifts"
|
||||
by_officer:
|
||||
new_assignment: "New shift"
|
||||
date: "Date"
|
||||
booth: "Booth"
|
||||
assignment: "Assignment"
|
||||
select_date: "Select day"
|
||||
select_booth: "Select booth"
|
||||
add_assignment: "Add shift"
|
||||
remove_assignment: "Remove"
|
||||
assignments: "Officing shifts in this poll"
|
||||
no_assignments: "This user has no officing shifts in this poll."
|
||||
final_recounts: "Final recounts"
|
||||
final_recount: "Final recount (by officer)"
|
||||
poll_shifts:
|
||||
new:
|
||||
new_assignment: "New shift"
|
||||
date: "Date"
|
||||
officer: "Officer"
|
||||
assignment: "Assignment"
|
||||
select_date: "Select day"
|
||||
select_officer: "Select officer"
|
||||
add_assignment: "Add shift"
|
||||
remove_assignment: "Remove"
|
||||
assignments: "Shifts in this booth"
|
||||
no_assignments: "This booth has no shifts"
|
||||
flash:
|
||||
create: "Shift added"
|
||||
destroy: "Shift removed"
|
||||
poll_booth_assignments:
|
||||
flash:
|
||||
destroy: "Booth not assigned anymore"
|
||||
@@ -618,6 +623,8 @@ en:
|
||||
submit_button: "Update booth"
|
||||
show:
|
||||
location: "Location"
|
||||
booth:
|
||||
shifts: "Manage shifts"
|
||||
officials:
|
||||
edit:
|
||||
destroy: Remove 'Official' status
|
||||
|
||||
57
config/locales/en/community.yml
Normal file
@@ -0,0 +1,57 @@
|
||||
en:
|
||||
community:
|
||||
sidebar:
|
||||
title: Community
|
||||
description:
|
||||
proposal: Participate in the user community of this proposal.
|
||||
investment: Participate in the user community of this investment.
|
||||
button_to_access: Access the community
|
||||
show:
|
||||
title:
|
||||
proposal: Proposal community
|
||||
investment: Budget Investment community
|
||||
description:
|
||||
proposal: Participate in the community of this proposal. An active community can help to improve the content of the proposal and boost its dissemination to get more support.
|
||||
investment: Participate in the community of this budget investment. An active community can help to improve the content of the budget investment and boost its dissemination to get more support.
|
||||
create_first_community_topic:
|
||||
first_theme_not_logged_in: No issue yet available, participate creating the first one. Click on the create new topic button.
|
||||
first_theme: Create the first community topic
|
||||
sub_first_theme: To create a theme you have to %{link}
|
||||
sign_link: "access %{org_name}"
|
||||
tab:
|
||||
participants: Participants
|
||||
sidebar:
|
||||
participate: Participate
|
||||
new_topic: Create topic
|
||||
disabled_info_title: You need to be logged to create a new topic
|
||||
topic:
|
||||
edit_button: Edit
|
||||
comments:
|
||||
one: 1 comment
|
||||
other: "%{count} comments"
|
||||
zero: No comments
|
||||
topic:
|
||||
create: Create a topic
|
||||
edit: Edit Topic
|
||||
form:
|
||||
topic_title: Topic Title
|
||||
topic_description: Description
|
||||
new:
|
||||
submit_button: Create topic
|
||||
edit:
|
||||
submit_button: Edit topic
|
||||
create:
|
||||
submit_button: Create topic
|
||||
update:
|
||||
submit_button: Update topic
|
||||
show:
|
||||
tab:
|
||||
comments_tab: Comments
|
||||
sidebar:
|
||||
recommendations_title: Recommendations to create a topic
|
||||
recommendation_one: Do not write the topic title or whole sentences in capital letters. On the internet that is considered shouting. And no one likes to be yelled at.
|
||||
recommendation_two: Any topic or comment that implies an illegal action will be eliminated, also those that intend to sabotage the spaces of the subject, everything else is allowed.
|
||||
recommendation_three: Enjoy this space, the voices that fill it, it's yours too.
|
||||
topics:
|
||||
show:
|
||||
login_to_comment: You must %{signin} or %{signup} to leave a comment.
|
||||
@@ -64,6 +64,7 @@ en:
|
||||
most_voted: Most voted
|
||||
newest: Newest first
|
||||
oldest: Oldest first
|
||||
most_commented: Most commented
|
||||
select_order: Sort by
|
||||
show:
|
||||
return_to_commentable: 'Go back to '
|
||||
@@ -182,6 +183,7 @@ en:
|
||||
verification/sms: phone
|
||||
signature_sheet: Signature sheet
|
||||
document: Document
|
||||
topic: Topic
|
||||
geozones:
|
||||
none: All city
|
||||
all: All scopes
|
||||
|
||||
@@ -53,7 +53,6 @@ en:
|
||||
empty_questions: There aren't any questions
|
||||
participate: Participate in the debate
|
||||
header_full:
|
||||
title: Participate
|
||||
description: Description
|
||||
more_info: More information and context
|
||||
index:
|
||||
|
||||
@@ -13,6 +13,7 @@ en:
|
||||
spending_proposal: "Spending proposal created successfully. You can access it from %{activity}"
|
||||
budget_investment: "Budget Investment created successfully."
|
||||
signature_sheet: "Signature sheet created successfully"
|
||||
topic: "Topic created successfully."
|
||||
save_changes:
|
||||
notice: Changes saved
|
||||
update:
|
||||
@@ -23,6 +24,7 @@ en:
|
||||
proposal: "Proposal updated successfully."
|
||||
spending_proposal: "Investment project updated succesfully."
|
||||
budget_investment: "Investment project updated succesfully."
|
||||
topic: "Topic updated successfully."
|
||||
destroy:
|
||||
spending_proposal: "Spending proposal deleted succesfully."
|
||||
budget_investment: "Investment project deleted succesfully."
|
||||
|
||||
@@ -41,6 +41,7 @@ en:
|
||||
legislation: Legislation
|
||||
user:
|
||||
recommendations: Recommendeds
|
||||
community: Community on proposals and investments
|
||||
mailer_from_name: Origin email name
|
||||
mailer_from_address: Origin email address
|
||||
meta_description: "Site description (SEO)"
|
||||
|
||||
@@ -414,6 +414,7 @@ es:
|
||||
poll_officers: Presidentes de mesa
|
||||
polls: Votaciones
|
||||
poll_booths: Ubicación de urnas
|
||||
poll_shifts: Asignar turnos
|
||||
officials: Cargos públicos
|
||||
organizations: Organizaciones
|
||||
settings: Configuración global
|
||||
@@ -481,11 +482,6 @@ es:
|
||||
search: Buscar
|
||||
user_not_found: Usuario no encontrado
|
||||
poll_officer_assignments:
|
||||
flash:
|
||||
destroy: "Eliminado turno de presidente de mesa"
|
||||
create: "Añadido turno de presidente de mesa"
|
||||
error_destroy: "Se ha producido un error al eliminar el turno"
|
||||
error_create: "Se ha producido un error al intentar crear el turno"
|
||||
index:
|
||||
officers_title: "Listado de presidentes de mesa asignados"
|
||||
no_officers: "No hay presidentes de mesa asignados a esta votación."
|
||||
@@ -494,18 +490,27 @@ es:
|
||||
add_officer_assignments: "Añadir turnos como presidente de mesa"
|
||||
edit_officer_assignments: "Editar turnos"
|
||||
by_officer:
|
||||
new_assignment: "Nuevo turno"
|
||||
date: "Fecha"
|
||||
booth: "Urna"
|
||||
assignment: "Asignación"
|
||||
select_date: "Seleccionar día"
|
||||
select_booth: "Seleccionar urna"
|
||||
add_assignment: "Añadir turno"
|
||||
remove_assignment: "Eliminar turno"
|
||||
assignments: "Turnos como presidente de mesa en esta votación"
|
||||
no_assignments: "No tiene turnos como presidente de mesa en esta votación."
|
||||
final_recounts: "Recuentos finales"
|
||||
final_recount: "Recuento final (presidente de mesa)"
|
||||
poll_shifts:
|
||||
new:
|
||||
new_assignment: "Nuevo turno"
|
||||
date: "Fecha"
|
||||
officer: "Presidente de mesa"
|
||||
assignment: "Asignación"
|
||||
select_date: "Seleccionar día"
|
||||
select_officer: "Seleccionar presidente de mesa"
|
||||
add_assignment: "Añadir turno"
|
||||
remove_assignment: "Eliminar turno"
|
||||
assignments: "Turnos en esta urna"
|
||||
no_assignments: "Esta urna no tiene turnos asignados"
|
||||
flash:
|
||||
create: "Añadido turno de presidente de mesa"
|
||||
destroy: "Eliminado turno de presidente de mesa"
|
||||
poll_booth_assignments:
|
||||
flash:
|
||||
destroy: "Urna desasignada"
|
||||
@@ -618,6 +623,8 @@ es:
|
||||
submit_button: "Actualizar urna"
|
||||
show:
|
||||
location: "Ubicación"
|
||||
booth:
|
||||
shifts: "Asignar turnos"
|
||||
officials:
|
||||
edit:
|
||||
destroy: Eliminar condición de 'Cargo Público'
|
||||
|
||||
57
config/locales/es/community.yml
Normal file
@@ -0,0 +1,57 @@
|
||||
es:
|
||||
community:
|
||||
sidebar:
|
||||
title: Comunidad
|
||||
description:
|
||||
proposal: Participa en la comunidad de usuarios de esta propuesta.
|
||||
investment: Participa en la comunidad de usuarios de este proyecto de inversión.
|
||||
button_to_access: Acceder a la comunidad
|
||||
show:
|
||||
title:
|
||||
proposal: Comunidad de la propuesta
|
||||
investment: Comunidad del presupuesto participativo
|
||||
description:
|
||||
proposal: Participa en la comunidad de esta propuesta. Una comunidad activa puede ayudar a mejorar el contenido de la propuesta así como a dinamizar su difusión para conseguir más apoyos.
|
||||
investment: Participa en la comunidad de este proyecto de inversión. Una comunidad activa puede ayudar a mejorar el contenido del proyecto de inversión así como a dinamizar su difusión para conseguir más apoyos.
|
||||
create_first_community_topic:
|
||||
first_theme_not_logged_in: Aún no hay ningun tema disponible, participa creando el primero. Haz click en el botón crear nuevo tema.
|
||||
first_theme: Crea el primer tema de la comunidad
|
||||
sub_first_theme: Para crear un tema tienes que %{link}
|
||||
sign_link: "acceder a %{org_name}"
|
||||
tab:
|
||||
participants: Participantes
|
||||
sidebar:
|
||||
participate: Participa
|
||||
new_topic: Crea un tema
|
||||
disabled_info_title: Necesitas estar logueado para crear un nuevo tema
|
||||
topic:
|
||||
edit_button: Editar
|
||||
comments:
|
||||
one: 1 Comentario
|
||||
other: "%{count} Comentarios"
|
||||
zero: Sin comentarios
|
||||
topic:
|
||||
create: Crear un tema
|
||||
edit: Editar tema
|
||||
form:
|
||||
topic_title: Titulo del tema
|
||||
topic_description: Descripción
|
||||
new:
|
||||
submit_button: Crear tema
|
||||
edit:
|
||||
submit_button: Guardar cambios
|
||||
create:
|
||||
submit_button: Crear tema
|
||||
update:
|
||||
submit_button: Actualizar tema
|
||||
show:
|
||||
tab:
|
||||
comments_tab: Comentarios
|
||||
sidebar:
|
||||
recommendations_title: Recomendaciones para crear un tema
|
||||
recommendation_one: No escribas el título del tema o frases enteras en mayúsculas. En internet eso se considera gritar. Y a nadie le gusta que le griten.
|
||||
recommendation_two: Cualquier tema o comentario que implique una acción ilegal será eliminada, también las que tengan la intención de sabotear los espacios del tema, todo lo demás está permitido.
|
||||
recommendation_three: Disfruta de este espacio, de las voces que lo llenan, también es tuyo
|
||||
topics:
|
||||
show:
|
||||
login_to_comment: Necesitas %{signin} o %{signup} para comentar.
|
||||
@@ -64,6 +64,7 @@ es:
|
||||
most_voted: Más votados
|
||||
newest: Más nuevos primero
|
||||
oldest: Más antiguos primero
|
||||
most_commented: Más comentados
|
||||
select_order: Ordenar por
|
||||
show:
|
||||
return_to_commentable: 'Volver a '
|
||||
@@ -182,6 +183,7 @@ es:
|
||||
verification/sms: el teléfono
|
||||
signature_sheet: la hoja de firmas
|
||||
document: el documento
|
||||
topic: Tema
|
||||
geozones:
|
||||
none: Toda la ciudad
|
||||
all: Todos los ámbitos de actuación
|
||||
|
||||
@@ -53,7 +53,6 @@ es:
|
||||
empty_questions: No hay preguntas
|
||||
participate: Realiza tus aportaciones al debate previo participando en los siguientes temas.
|
||||
header_full:
|
||||
title: Colabora en la elaboración de la normativa sobre
|
||||
description: En qué consiste
|
||||
more_info: Más información y contexto
|
||||
index:
|
||||
|
||||
@@ -13,6 +13,7 @@ es:
|
||||
spending_proposal: "Propuesta de inversión creada correctamente. Puedes acceder a ella desde %{activity}"
|
||||
budget_investment: "Propuesta de inversión creada correctamente."
|
||||
signature_sheet: "Hoja de firmas creada correctamente"
|
||||
topic: "Tema creado correctamente."
|
||||
save_changes:
|
||||
notice: Cambios guardados
|
||||
update:
|
||||
@@ -23,6 +24,7 @@ es:
|
||||
poll_booth: "Urna actualizada correctamente."
|
||||
spending_proposal: "Propuesta de inversión actualizada correctamente."
|
||||
budget_investment: "Propuesta de inversión actualizada correctamente"
|
||||
topic: "Tema actualizado correctamente."
|
||||
destroy:
|
||||
spending_proposal: "Propuesta de inversión eliminada."
|
||||
budget_investment: "Propuesta de inversión eliminada."
|
||||
|
||||
@@ -41,6 +41,7 @@ es:
|
||||
legislation: Legislación
|
||||
user:
|
||||
recommendations: Recomendaciones
|
||||
community: Comunidad en propuestas y proyectos de inversión
|
||||
mailer_from_name: Nombre email remitente
|
||||
mailer_from_address: Dirección email remitente
|
||||
meta_description: "Descripción del sitio (SEO)"
|
||||
|
||||
@@ -156,6 +156,10 @@ Rails.application.routes.draw do
|
||||
|
||||
resource :verification, controller: "verification", only: [:show]
|
||||
|
||||
resources :communities, only: [:show] do
|
||||
resources :topics
|
||||
end
|
||||
|
||||
scope module: :verification do
|
||||
resource :residence, controller: "residence", only: [:new, :create]
|
||||
resource :sms, controller: "sms", only: [:new, :create, :edit, :update]
|
||||
@@ -164,6 +168,7 @@ Rails.application.routes.draw do
|
||||
resource :letter, controller: "letter", only: [:new, :create, :show, :edit, :update]
|
||||
end
|
||||
|
||||
|
||||
namespace :admin do
|
||||
root to: "dashboard#index"
|
||||
resources :organizations, only: :index do
|
||||
@@ -281,7 +286,10 @@ Rails.application.routes.draw do
|
||||
get :search, on: :collection
|
||||
end
|
||||
|
||||
resources :booths
|
||||
resources :booths do
|
||||
resources :shifts
|
||||
end
|
||||
|
||||
resources :questions
|
||||
end
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ Setting.create(key: 'feature.google_login', value: "true")
|
||||
Setting.create(key: 'feature.signature_sheets', value: "true")
|
||||
Setting.create(key: 'feature.legislation', value: "true")
|
||||
Setting.create(key: 'feature.user.recommendations', value: "true")
|
||||
Setting.create(key: 'feature.community', value: "true")
|
||||
Setting.create(key: 'per_page_code_head', value: "")
|
||||
Setting.create(key: 'per_page_code_body', value: "")
|
||||
Setting.create(key: 'comments_body_max_length', value: '1000')
|
||||
|
||||
15
db/migrate/20170724190805_create_poll_shifts.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
class CreatePollShifts < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :poll_shifts do |t|
|
||||
t.integer :booth_id
|
||||
t.integer :officer_id
|
||||
t.date :date
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_index :poll_shifts, :booth_id
|
||||
add_index :poll_shifts, :officer_id
|
||||
add_index :poll_shifts, [:booth_id, :officer_id]
|
||||
end
|
||||
end
|
||||
7
db/migrate/20170804170049_create_community.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
class CreateCommunity < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :communities do |t|
|
||||
t.timestamps null: false
|
||||
end
|
||||
end
|
||||
end
|
||||
5
db/migrate/20170804171325_add_community_to_proposal.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
class AddCommunityToProposal < ActiveRecord::Migration
|
||||
def change
|
||||
add_reference :proposals, :community, index: true, foreign_key: true
|
||||
end
|
||||
end
|
||||
13
db/migrate/20170807082243_create_topics.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
class CreateTopics < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :topics do |t|
|
||||
t.string :title, null: false
|
||||
t.text :description
|
||||
t.integer :author_id
|
||||
t.integer "comments_count", default: 0
|
||||
t.references :community, index: true
|
||||
t.datetime :hidden_at, index: true
|
||||
t.timestamps null: false
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddCommunityToBudgetInvestments < ActiveRecord::Migration
|
||||
def change
|
||||
add_reference :budget_investments, :community, index: true, foreign_key: true
|
||||
end
|
||||
end
|
||||
41
db/schema.rb
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20170720092638) do
|
||||
ActiveRecord::Schema.define(version: 20170822144743) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
@@ -160,10 +160,12 @@ ActiveRecord::Schema.define(version: 20170720092638) do
|
||||
t.integer "previous_heading_id"
|
||||
t.boolean "winner", default: false
|
||||
t.boolean "incompatible", default: false
|
||||
t.integer "community_id"
|
||||
end
|
||||
|
||||
add_index "budget_investments", ["administrator_id"], name: "index_budget_investments_on_administrator_id", using: :btree
|
||||
add_index "budget_investments", ["author_id"], name: "index_budget_investments_on_author_id", using: :btree
|
||||
add_index "budget_investments", ["community_id"], name: "index_budget_investments_on_community_id", using: :btree
|
||||
add_index "budget_investments", ["heading_id"], name: "index_budget_investments_on_heading_id", using: :btree
|
||||
add_index "budget_investments", ["tsv"], name: "index_budget_investments_on_tsv", using: :gin
|
||||
|
||||
@@ -236,6 +238,11 @@ ActiveRecord::Schema.define(version: 20170720092638) do
|
||||
add_index "comments", ["hidden_at"], name: "index_comments_on_hidden_at", using: :btree
|
||||
add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree
|
||||
|
||||
create_table "communities", force: :cascade do |t|
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
create_table "debates", force: :cascade do |t|
|
||||
t.string "title", limit: 80
|
||||
t.text "description"
|
||||
@@ -669,6 +676,18 @@ ActiveRecord::Schema.define(version: 20170720092638) do
|
||||
add_index "poll_questions", ["proposal_id"], name: "index_poll_questions_on_proposal_id", using: :btree
|
||||
add_index "poll_questions", ["tsv"], name: "index_poll_questions_on_tsv", using: :gin
|
||||
|
||||
create_table "poll_shifts", force: :cascade do |t|
|
||||
t.integer "booth_id"
|
||||
t.integer "officer_id"
|
||||
t.date "date"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
add_index "poll_shifts", ["booth_id", "officer_id"], name: "index_poll_shifts_on_booth_id_and_officer_id", using: :btree
|
||||
add_index "poll_shifts", ["booth_id"], name: "index_poll_shifts_on_booth_id", using: :btree
|
||||
add_index "poll_shifts", ["officer_id"], name: "index_poll_shifts_on_officer_id", using: :btree
|
||||
|
||||
create_table "poll_voters", force: :cascade do |t|
|
||||
t.string "document_number"
|
||||
t.string "document_type"
|
||||
@@ -749,11 +768,13 @@ ActiveRecord::Schema.define(version: 20170720092638) do
|
||||
t.datetime "retired_at"
|
||||
t.string "retired_reason"
|
||||
t.text "retired_explanation"
|
||||
t.integer "community_id"
|
||||
end
|
||||
|
||||
add_index "proposals", ["author_id", "hidden_at"], name: "index_proposals_on_author_id_and_hidden_at", using: :btree
|
||||
add_index "proposals", ["author_id"], name: "index_proposals_on_author_id", using: :btree
|
||||
add_index "proposals", ["cached_votes_up"], name: "index_proposals_on_cached_votes_up", using: :btree
|
||||
add_index "proposals", ["community_id"], name: "index_proposals_on_community_id", using: :btree
|
||||
add_index "proposals", ["confidence_score"], name: "index_proposals_on_confidence_score", using: :btree
|
||||
add_index "proposals", ["geozone_id"], name: "index_proposals_on_geozone_id", using: :btree
|
||||
add_index "proposals", ["hidden_at"], name: "index_proposals_on_hidden_at", using: :btree
|
||||
@@ -883,6 +904,20 @@ ActiveRecord::Schema.define(version: 20170720092638) do
|
||||
add_index "tags", ["proposals_count"], name: "index_tags_on_proposals_count", using: :btree
|
||||
add_index "tags", ["spending_proposals_count"], name: "index_tags_on_spending_proposals_count", using: :btree
|
||||
|
||||
create_table "topics", force: :cascade do |t|
|
||||
t.string "title", null: false
|
||||
t.text "description"
|
||||
t.integer "author_id"
|
||||
t.integer "comments_count", default: 0
|
||||
t.integer "community_id"
|
||||
t.datetime "hidden_at"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
add_index "topics", ["community_id"], name: "index_topics_on_community_id", using: :btree
|
||||
add_index "topics", ["hidden_at"], name: "index_topics_on_hidden_at", using: :btree
|
||||
|
||||
create_table "users", force: :cascade do |t|
|
||||
t.string "email", default: ""
|
||||
t.string "encrypted_password", default: "", null: false
|
||||
@@ -936,7 +971,7 @@ ActiveRecord::Schema.define(version: 20170720092638) do
|
||||
t.boolean "email_digest", default: true
|
||||
t.boolean "email_on_direct_message", default: true
|
||||
t.boolean "official_position_badge", default: false
|
||||
t.datetime "password_changed_at", default: '2017-07-21 18:09:48', null: false
|
||||
t.datetime "password_changed_at", default: '2017-08-07 11:14:09', null: false
|
||||
t.boolean "created_from_signature", default: false
|
||||
t.integer "failed_email_digests_count", default: 0
|
||||
t.text "former_users_data_log", default: ""
|
||||
@@ -1031,6 +1066,7 @@ ActiveRecord::Schema.define(version: 20170720092638) do
|
||||
add_foreign_key "administrators", "users"
|
||||
add_foreign_key "annotations", "legacy_legislations"
|
||||
add_foreign_key "annotations", "users"
|
||||
add_foreign_key "budget_investments", "communities"
|
||||
add_foreign_key "documents", "users"
|
||||
add_foreign_key "failed_census_calls", "poll_officers"
|
||||
add_foreign_key "failed_census_calls", "users"
|
||||
@@ -1062,6 +1098,7 @@ ActiveRecord::Schema.define(version: 20170720092638) do
|
||||
add_foreign_key "poll_voters", "polls"
|
||||
add_foreign_key "poll_white_results", "poll_booth_assignments", column: "booth_assignment_id"
|
||||
add_foreign_key "poll_white_results", "poll_officer_assignments", column: "officer_assignment_id"
|
||||
add_foreign_key "proposals", "communities"
|
||||
add_foreign_key "users", "geozones"
|
||||
add_foreign_key "valuators", "users"
|
||||
end
|
||||
|
||||
@@ -79,7 +79,8 @@ Setting['feature.public_stats'] = true
|
||||
Setting['feature.budgets'] = true
|
||||
Setting['feature.signature_sheets'] = true
|
||||
Setting['feature.legislation'] = true
|
||||
Setting['feature.user.recommendations'] = nil
|
||||
Setting['feature.user.recommendations'] = true
|
||||
Setting['feature.community'] = true
|
||||
|
||||
# Spending proposals feature flags
|
||||
Setting['feature.spending_proposal_features.voting_allowed'] = nil
|
||||
|
||||
21
lib/tasks/communities.rake
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace :communities do
|
||||
|
||||
desc "Associate community to proposals and budget investments"
|
||||
task associate_community: :environment do
|
||||
|
||||
Proposal.all.each do |proposal|
|
||||
if proposal.community.blank?
|
||||
community = Community.create
|
||||
proposal.update(community_id: community.id)
|
||||
end
|
||||
end
|
||||
|
||||
Budget::Investment.all.each do |investment|
|
||||
if investment.community.blank?
|
||||
community = Community.create
|
||||
investment.update(community_id: community.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -449,6 +449,11 @@ FactoryGirl.define do
|
||||
starts_at { 1.month.ago }
|
||||
ends_at { 1.month.from_now }
|
||||
|
||||
trait :current do
|
||||
starts_at { 2.days.ago }
|
||||
ends_at { 2.days.from_now }
|
||||
end
|
||||
|
||||
trait :incoming do
|
||||
starts_at { 2.days.from_now }
|
||||
ends_at { 1.month.from_now }
|
||||
@@ -492,6 +497,12 @@ FactoryGirl.define do
|
||||
end
|
||||
end
|
||||
|
||||
factory :poll_shift, class: 'Poll::Shift' do
|
||||
association :booth, factory: :poll_booth
|
||||
association :officer, factory: :poll_officer
|
||||
date Date.current
|
||||
end
|
||||
|
||||
factory :poll_final_recount, class: 'Poll::FinalRecount' do
|
||||
association :officer_assignment, factory: [:poll_officer_assignment, :final]
|
||||
association :booth_assignment, factory: :poll_booth_assignment
|
||||
@@ -784,4 +795,11 @@ LOREM_IPSUM
|
||||
locale "en"
|
||||
body "Some top links content"
|
||||
end
|
||||
|
||||
factory :topic do
|
||||
sequence(:title) { |n| "Topic title #{n}" }
|
||||
sequence(:description) { |n| "Description as comment #{n}" }
|
||||
association :author, factory: :user
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Admin officer assignments in poll' do
|
||||
|
||||
background do
|
||||
admin = create(:administrator)
|
||||
login_as(admin.user)
|
||||
end
|
||||
|
||||
scenario 'Assign officer to poll', :js do
|
||||
booth_assignment = create(:poll_booth_assignment)
|
||||
officer = create(:poll_officer)
|
||||
|
||||
visit admin_poll_path(booth_assignment.poll)
|
||||
within('#poll-resources') do
|
||||
click_link 'Officers (0)'
|
||||
end
|
||||
|
||||
expect(page).to have_content 'There are no officers assigned to this poll'
|
||||
|
||||
fill_in 'search-officers', with: officer.name
|
||||
click_button 'Search'
|
||||
|
||||
within('#search-officers-results') do
|
||||
click_link 'Add shifts as officer'
|
||||
end
|
||||
|
||||
expect(page).to have_content 'This user has no officing shifts in this poll'
|
||||
expect(page).to have_content officer.name
|
||||
expect(page).to have_content booth_assignment.poll.name
|
||||
|
||||
within('#officer_assignment_form') do
|
||||
select I18n.l(booth_assignment.poll.ends_at.to_date, format: :long), from: 'date'
|
||||
select "#{booth_assignment.booth.name} (#{booth_assignment.booth.location})", from: 'booth_id'
|
||||
click_button 'Add shift'
|
||||
end
|
||||
|
||||
expect(page).to have_content 'Officing shift added'
|
||||
expect(page).to_not have_content 'This user has no officing shifts in this poll'
|
||||
|
||||
visit admin_poll_path(booth_assignment.poll)
|
||||
within('#poll-resources') do
|
||||
click_link 'Officers (1)'
|
||||
end
|
||||
|
||||
expect(page).to_not have_content 'There are no officers in this poll'
|
||||
expect(page).to have_content officer.name
|
||||
expect(page).to have_content officer.email
|
||||
end
|
||||
|
||||
scenario 'Remove officer assignment from poll' do
|
||||
officer_assignment = create(:poll_officer_assignment)
|
||||
poll = officer_assignment.booth_assignment.poll
|
||||
booth = officer_assignment.booth_assignment.booth
|
||||
officer = officer_assignment.officer
|
||||
|
||||
visit by_officer_admin_poll_officer_assignments_path(poll, officer_id: officer.id)
|
||||
|
||||
expect(page).to_not have_content 'This user has no officing shifts in this poll'
|
||||
within("#poll_officer_assignment_#{officer_assignment.id}") do
|
||||
expect(page).to have_content booth.name
|
||||
click_link 'Remove'
|
||||
end
|
||||
|
||||
expect(page).to have_content 'Officing shift removed'
|
||||
expect(page).to have_content 'This user has no officing shifts in this poll'
|
||||
end
|
||||
|
||||
scenario 'Index view shows recounts info for officer' do
|
||||
booth_assignment = create(:poll_booth_assignment)
|
||||
poll = booth_assignment.poll
|
||||
officer = create(:poll_officer)
|
||||
create(:poll_officer_assignment,
|
||||
booth_assignment: booth_assignment,
|
||||
officer: officer,
|
||||
date: poll.starts_at)
|
||||
final_officer_assignment = create(:poll_officer_assignment, :final,
|
||||
booth_assignment: booth_assignment,
|
||||
officer: officer,
|
||||
date: poll.ends_at + 1.day)
|
||||
create(:poll_final_recount,
|
||||
booth_assignment: booth_assignment,
|
||||
officer_assignment: final_officer_assignment,
|
||||
date: poll.ends_at,
|
||||
count: 9876)
|
||||
|
||||
visit by_officer_admin_poll_officer_assignments_path(poll, officer_id: officer.id)
|
||||
|
||||
within('#final_recount_list') { expect(page).to have_content('9876') }
|
||||
end
|
||||
end
|
||||
88
spec/features/admin/poll/shifts_spec.rb
Normal file
@@ -0,0 +1,88 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Admin shifts' do
|
||||
|
||||
background do
|
||||
admin = create(:administrator)
|
||||
login_as(admin.user)
|
||||
end
|
||||
|
||||
scenario "Show" do
|
||||
poll = create(:poll)
|
||||
officer = create(:poll_officer)
|
||||
|
||||
booth1 = create(:poll_booth)
|
||||
booth2 = create(:poll_booth)
|
||||
|
||||
shift1 = create(:poll_shift, officer: officer, booth: booth1, date: Date.today)
|
||||
shift2 = create(:poll_shift, officer: officer, booth: booth2, date: Date.tomorrow)
|
||||
|
||||
visit new_admin_booth_shift_path(booth1)
|
||||
|
||||
expect(page).to have_css(".shift", count: 1)
|
||||
expect(page).to have_content I18n.l(Date.today, format: :long)
|
||||
expect(page).to have_content officer.name
|
||||
|
||||
visit new_admin_booth_shift_path(booth2)
|
||||
|
||||
expect(page).to have_css(".shift", count: 1)
|
||||
expect(page).to have_content I18n.l(Date.tomorrow, format: :long)
|
||||
expect(page).to have_content officer.name
|
||||
end
|
||||
|
||||
scenario "Create" do
|
||||
poll = create(:poll)
|
||||
booth = create(:poll_booth)
|
||||
officer = create(:poll_officer)
|
||||
|
||||
visit admin_booths_path
|
||||
|
||||
within("#booth_#{booth.id}") do
|
||||
click_link "Manage shifts"
|
||||
end
|
||||
|
||||
select I18n.l(poll.starts_at.to_date, format: :long), from: 'shift_date'
|
||||
select officer.name, from: 'shift_officer_id'
|
||||
click_button "Add shift"
|
||||
|
||||
expect(page).to have_content "Shift added"
|
||||
|
||||
within("#shifts") do
|
||||
expect(page).to have_css(".shift", count: 1)
|
||||
expect(page).to have_content(I18n.l(poll.starts_at.to_date, format: :long))
|
||||
expect(page).to have_content(officer.name)
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Destroy" do
|
||||
poll = create(:poll)
|
||||
booth = create(:poll_booth)
|
||||
officer = create(:poll_officer)
|
||||
|
||||
shift = create(:poll_shift, officer: officer, booth: booth)
|
||||
|
||||
visit admin_booths_path
|
||||
|
||||
within("#booth_#{booth.id}") do
|
||||
click_link "Manage shifts"
|
||||
end
|
||||
|
||||
expect(page).to have_css(".shift", count: 1)
|
||||
within("#shift_#{shift.id}") do
|
||||
click_link "Remove"
|
||||
end
|
||||
|
||||
expect(page).to have_content "Shift removed"
|
||||
expect(page).to have_css(".shift", count: 0)
|
||||
end
|
||||
|
||||
scenario "Empty" do
|
||||
poll = create(:poll)
|
||||
booth = create(:poll_booth)
|
||||
|
||||
visit new_admin_booth_shift_path(booth)
|
||||
|
||||
expect(page).to have_content "This booth has no shifts"
|
||||
end
|
||||
|
||||
end
|
||||
@@ -329,6 +329,22 @@ feature 'Budget Investments' do
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Can access the community' do
|
||||
Setting['feature.community'] = true
|
||||
|
||||
investment = create(:budget_investment, heading: heading)
|
||||
visit budget_investment_path(budget_id: budget.id, id: investment.id)
|
||||
expect(page).to have_content "Access the community"
|
||||
|
||||
Setting['feature.community'] = false
|
||||
end
|
||||
|
||||
scenario 'Can not access the community' do
|
||||
investment = create(:budget_investment, heading: heading)
|
||||
visit budget_investment_path(budget_id: budget.id, id: investment.id)
|
||||
expect(page).not_to have_content "Access the community"
|
||||
end
|
||||
|
||||
scenario "Don't display flaggable buttons" do
|
||||
investment = create(:budget_investment, heading: heading)
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ feature 'Commenting proposals' do
|
||||
expect(page).to have_content parent_comment.body
|
||||
expect(page).to have_content first_child.body
|
||||
expect(page).to have_content second_child.body
|
||||
|
||||
expect(page).to have_link "Go back to #{proposal.title}", href: proposal_path(proposal)
|
||||
end
|
||||
|
||||
|
||||
552
spec/features/comments/topics_spec.rb
Normal file
@@ -0,0 +1,552 @@
|
||||
require 'rails_helper'
|
||||
include ActionView::Helpers::DateHelper
|
||||
|
||||
feature 'Commenting topics' do
|
||||
let(:user) { create :user }
|
||||
let(:proposal) { create :proposal }
|
||||
|
||||
scenario 'Index', :js do
|
||||
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
3.times { create(:comment, commentable: topic) }
|
||||
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
expect(page).to have_css('.comment', count: 3)
|
||||
|
||||
comment = Comment.last
|
||||
within first('.comment') do
|
||||
expect(page).to have_content comment.user.name
|
||||
expect(page).to have_content I18n.l(comment.created_at, format: :datetime)
|
||||
expect(page).to have_content comment.body
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Show', :js do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
parent_comment = create(:comment, commentable: topic)
|
||||
first_child = create(:comment, commentable: topic, parent: parent_comment)
|
||||
second_child = create(:comment, commentable: topic, parent: parent_comment)
|
||||
|
||||
visit comment_path(parent_comment)
|
||||
|
||||
expect(page).to have_css(".comment", count: 3)
|
||||
expect(page).to have_content parent_comment.body
|
||||
expect(page).to have_content first_child.body
|
||||
expect(page).to have_content second_child.body
|
||||
|
||||
expect(page).to have_link "Go back to #{topic.title}", href: community_topic_path(community, topic)
|
||||
end
|
||||
|
||||
scenario 'Collapsable comments', :js do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
parent_comment = create(:comment, body: "Main comment", commentable: topic)
|
||||
child_comment = create(:comment, body: "First subcomment", commentable: topic, parent: parent_comment)
|
||||
grandchild_comment = create(:comment, body: "Last subcomment", commentable: topic, parent: child_comment)
|
||||
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
expect(page).to have_css('.comment', count: 3)
|
||||
|
||||
find("#comment_#{child_comment.id}_children_arrow").trigger('click')
|
||||
|
||||
expect(page).to have_css('.comment', count: 2)
|
||||
expect(page).to_not have_content grandchild_comment.body
|
||||
|
||||
find("#comment_#{child_comment.id}_children_arrow").trigger('click')
|
||||
|
||||
expect(page).to have_css('.comment', count: 3)
|
||||
expect(page).to have_content grandchild_comment.body
|
||||
|
||||
find("#comment_#{parent_comment.id}_children_arrow").trigger('click')
|
||||
|
||||
expect(page).to have_css('.comment', count: 1)
|
||||
expect(page).to_not have_content child_comment.body
|
||||
expect(page).to_not have_content grandchild_comment.body
|
||||
end
|
||||
|
||||
scenario 'Comment order' do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
c1 = create(:comment, :with_confidence_score, commentable: topic, cached_votes_up: 100,
|
||||
cached_votes_total: 120, created_at: Time.current - 2)
|
||||
c2 = create(:comment, :with_confidence_score, commentable: topic, cached_votes_up: 10,
|
||||
cached_votes_total: 12, created_at: Time.current - 1)
|
||||
c3 = create(:comment, :with_confidence_score, commentable: topic, cached_votes_up: 1,
|
||||
cached_votes_total: 2, created_at: Time.current)
|
||||
|
||||
visit community_topic_path(community, topic, order: :most_voted)
|
||||
|
||||
expect(c1.body).to appear_before(c2.body)
|
||||
expect(c2.body).to appear_before(c3.body)
|
||||
|
||||
visit community_topic_path(community, topic, order: :newest)
|
||||
|
||||
expect(c3.body).to appear_before(c2.body)
|
||||
expect(c2.body).to appear_before(c1.body)
|
||||
|
||||
visit community_topic_path(community, topic, order: :oldest)
|
||||
|
||||
expect(c1.body).to appear_before(c2.body)
|
||||
expect(c2.body).to appear_before(c3.body)
|
||||
end
|
||||
|
||||
scenario 'Creation date works differently in roots and in child comments, when sorting by confidence_score' do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
old_root = create(:comment, commentable: topic, created_at: Time.current - 10)
|
||||
new_root = create(:comment, commentable: topic, created_at: Time.current)
|
||||
old_child = create(:comment, commentable: topic, parent_id: new_root.id, created_at: Time.current - 10)
|
||||
new_child = create(:comment, commentable: topic, parent_id: new_root.id, created_at: Time.current)
|
||||
|
||||
visit community_topic_path(community, topic, order: :most_voted)
|
||||
|
||||
expect(new_root.body).to appear_before(old_root.body)
|
||||
expect(old_child.body).to appear_before(new_child.body)
|
||||
|
||||
visit community_topic_path(community, topic, order: :newest)
|
||||
|
||||
expect(new_root.body).to appear_before(old_root.body)
|
||||
expect(new_child.body).to appear_before(old_child.body)
|
||||
|
||||
visit community_topic_path(community, topic, order: :oldest)
|
||||
|
||||
expect(old_root.body).to appear_before(new_root.body)
|
||||
expect(old_child.body).to appear_before(new_child.body)
|
||||
end
|
||||
|
||||
scenario 'Turns links into html links' do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
create :comment, commentable: topic, body: 'Built with http://rubyonrails.org/'
|
||||
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
within first('.comment') do
|
||||
expect(page).to have_content 'Built with http://rubyonrails.org/'
|
||||
expect(page).to have_link('http://rubyonrails.org/', href: 'http://rubyonrails.org/')
|
||||
expect(find_link('http://rubyonrails.org/')[:rel]).to eq('nofollow')
|
||||
expect(find_link('http://rubyonrails.org/')[:target]).to eq('_blank')
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Sanitizes comment body for security' do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
create :comment, commentable: topic,
|
||||
body: "<script>alert('hola')</script> <a href=\"javascript:alert('sorpresa!')\">click me<a/> http://www.url.com"
|
||||
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
within first('.comment') do
|
||||
expect(page).to have_content "click me http://www.url.com"
|
||||
expect(page).to have_link('http://www.url.com', href: 'http://www.url.com')
|
||||
expect(page).not_to have_link('click me')
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Paginated comments' do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
per_page = 10
|
||||
(per_page + 2).times { create(:comment, commentable: topic)}
|
||||
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
expect(page).to have_css('.comment', count: per_page)
|
||||
within("ul.pagination") do
|
||||
expect(page).to have_content("1")
|
||||
expect(page).to have_content("2")
|
||||
expect(page).to_not have_content("3")
|
||||
click_link "Next", exact: false
|
||||
end
|
||||
|
||||
expect(page).to have_css('.comment', count: 2)
|
||||
end
|
||||
|
||||
feature 'Not logged user' do
|
||||
scenario 'can not see comments forms' do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
create(:comment, commentable: topic)
|
||||
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
expect(page).to have_content 'You must Sign in or Sign up to leave a comment'
|
||||
within('#comments') do
|
||||
expect(page).to_not have_content 'Write a comment'
|
||||
expect(page).to_not have_content 'Reply'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Create', :js do
|
||||
login_as(user)
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
fill_in "comment-body-topic_#{topic.id}", with: 'Have you thought about...?'
|
||||
click_button 'Publish comment'
|
||||
|
||||
within "#comments" do
|
||||
expect(page).to have_content 'Have you thought about...?'
|
||||
end
|
||||
|
||||
within "#tab-comments-label" do
|
||||
expect(page).to have_content 'Comments (1)'
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Errors on create', :js do
|
||||
login_as(user)
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
click_button 'Publish comment'
|
||||
|
||||
expect(page).to have_content "Can't be blank"
|
||||
end
|
||||
|
||||
scenario 'Reply', :js do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
citizen = create(:user, username: 'Ana')
|
||||
manuela = create(:user, username: 'Manuela')
|
||||
comment = create(:comment, commentable: topic, user: citizen)
|
||||
|
||||
login_as(manuela)
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
click_link "Reply"
|
||||
|
||||
within "#js-comment-form-comment_#{comment.id}" do
|
||||
fill_in "comment-body-comment_#{comment.id}", with: 'It will be done next week.'
|
||||
click_button 'Publish reply'
|
||||
end
|
||||
|
||||
within "#comment_#{comment.id}" do
|
||||
expect(page).to have_content 'It will be done next week.'
|
||||
end
|
||||
|
||||
expect(page).to_not have_selector("#js-comment-form-comment_#{comment.id}", visible: true)
|
||||
end
|
||||
|
||||
scenario 'Errors on reply', :js do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
comment = create(:comment, commentable: topic, user: user)
|
||||
|
||||
login_as(user)
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
click_link "Reply"
|
||||
|
||||
within "#js-comment-form-comment_#{comment.id}" do
|
||||
click_button 'Publish reply'
|
||||
expect(page).to have_content "Can't be blank"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
scenario "N replies", :js do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
parent = create(:comment, commentable: topic)
|
||||
|
||||
7.times do
|
||||
create(:comment, commentable: topic, parent: parent)
|
||||
parent = parent.children.first
|
||||
end
|
||||
|
||||
visit community_topic_path(community, topic)
|
||||
expect(page).to have_css(".comment.comment.comment.comment.comment.comment.comment.comment")
|
||||
end
|
||||
|
||||
scenario "Flagging as inappropriate", :js do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
comment = create(:comment, commentable: topic)
|
||||
|
||||
login_as(user)
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
within "#comment_#{comment.id}" do
|
||||
page.find("#flag-expand-comment-#{comment.id}").click
|
||||
page.find("#flag-comment-#{comment.id}").click
|
||||
|
||||
expect(page).to have_css("#unflag-expand-comment-#{comment.id}")
|
||||
end
|
||||
|
||||
expect(Flag.flagged?(user, comment)).to be
|
||||
end
|
||||
|
||||
scenario "Undoing flagging as inappropriate", :js do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
comment = create(:comment, commentable: topic)
|
||||
Flag.flag(user, comment)
|
||||
|
||||
login_as(user)
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
within "#comment_#{comment.id}" do
|
||||
page.find("#unflag-expand-comment-#{comment.id}").click
|
||||
page.find("#unflag-comment-#{comment.id}").click
|
||||
|
||||
expect(page).to have_css("#flag-expand-comment-#{comment.id}")
|
||||
end
|
||||
|
||||
expect(Flag.flagged?(user, comment)).to_not be
|
||||
end
|
||||
|
||||
scenario "Flagging turbolinks sanity check", :js do
|
||||
Setting['feature.community'] = true
|
||||
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community, title: "Should we change the world?")
|
||||
comment = create(:comment, commentable: topic)
|
||||
|
||||
login_as(user)
|
||||
visit community_path(community)
|
||||
click_link "Should we change the world?"
|
||||
|
||||
within "#comment_#{comment.id}" do
|
||||
page.find("#flag-expand-comment-#{comment.id}").click
|
||||
expect(page).to have_selector("#flag-comment-#{comment.id}")
|
||||
end
|
||||
|
||||
Setting['feature.community'] = nil
|
||||
end
|
||||
|
||||
scenario "Erasing a comment's author" do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
comment = create(:comment, commentable: topic, body: "this should be visible")
|
||||
comment.user.erase
|
||||
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
within "#comment_#{comment.id}" do
|
||||
expect(page).to have_content('User deleted')
|
||||
expect(page).to have_content('this should be visible')
|
||||
end
|
||||
end
|
||||
|
||||
feature "Moderators" do
|
||||
scenario "can create comment as a moderator", :js do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
moderator = create(:moderator)
|
||||
|
||||
login_as(moderator.user)
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
fill_in "comment-body-topic_#{topic.id}", with: "I am moderating!"
|
||||
check "comment-as-moderator-topic_#{topic.id}"
|
||||
click_button "Publish comment"
|
||||
|
||||
within "#comments" do
|
||||
expect(page).to have_content "I am moderating!"
|
||||
expect(page).to have_content "Moderator ##{moderator.id}"
|
||||
expect(page).to have_css "div.is-moderator"
|
||||
expect(page).to have_css "img.moderator-avatar"
|
||||
end
|
||||
end
|
||||
|
||||
scenario "can create reply as a moderator", :js do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
citizen = create(:user, username: "Ana")
|
||||
manuela = create(:user, username: "Manuela")
|
||||
moderator = create(:moderator, user: manuela)
|
||||
comment = create(:comment, commentable: topic, user: citizen)
|
||||
|
||||
login_as(manuela)
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
click_link "Reply"
|
||||
|
||||
within "#js-comment-form-comment_#{comment.id}" do
|
||||
fill_in "comment-body-comment_#{comment.id}", with: "I am moderating!"
|
||||
check "comment-as-moderator-comment_#{comment.id}"
|
||||
click_button 'Publish reply'
|
||||
end
|
||||
|
||||
within "#comment_#{comment.id}" do
|
||||
expect(page).to have_content "I am moderating!"
|
||||
expect(page).to have_content "Moderator ##{moderator.id}"
|
||||
expect(page).to have_css "div.is-moderator"
|
||||
expect(page).to have_css "img.moderator-avatar"
|
||||
end
|
||||
|
||||
expect(page).to_not have_selector("#js-comment-form-comment_#{comment.id}", visible: true)
|
||||
end
|
||||
|
||||
scenario "can not comment as an administrator" do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
moderator = create(:moderator)
|
||||
|
||||
login_as(moderator.user)
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
expect(page).to_not have_content "Comment as administrator"
|
||||
end
|
||||
end
|
||||
|
||||
feature "Administrators" do
|
||||
scenario "can create comment as an administrator", :js do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
admin = create(:administrator)
|
||||
|
||||
login_as(admin.user)
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
fill_in "comment-body-topic_#{topic.id}", with: "I am your Admin!"
|
||||
check "comment-as-administrator-topic_#{topic.id}"
|
||||
click_button "Publish comment"
|
||||
|
||||
within "#comments" do
|
||||
expect(page).to have_content "I am your Admin!"
|
||||
expect(page).to have_content "Administrator ##{admin.id}"
|
||||
expect(page).to have_css "div.is-admin"
|
||||
expect(page).to have_css "img.admin-avatar"
|
||||
end
|
||||
end
|
||||
|
||||
scenario "can create reply as an administrator", :js do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
citizen = create(:user, username: "Ana")
|
||||
manuela = create(:user, username: "Manuela")
|
||||
admin = create(:administrator, user: manuela)
|
||||
comment = create(:comment, commentable: topic, user: citizen)
|
||||
|
||||
login_as(manuela)
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
click_link "Reply"
|
||||
|
||||
within "#js-comment-form-comment_#{comment.id}" do
|
||||
fill_in "comment-body-comment_#{comment.id}", with: "Top of the world!"
|
||||
check "comment-as-administrator-comment_#{comment.id}"
|
||||
click_button 'Publish reply'
|
||||
end
|
||||
|
||||
within "#comment_#{comment.id}" do
|
||||
expect(page).to have_content "Top of the world!"
|
||||
expect(page).to have_content "Administrator ##{admin.id}"
|
||||
expect(page).to have_css "div.is-admin"
|
||||
expect(page).to have_css "img.admin-avatar"
|
||||
end
|
||||
|
||||
expect(page).to_not have_selector("#js-comment-form-comment_#{comment.id}", visible: true)
|
||||
end
|
||||
|
||||
scenario "can not comment as a moderator" do
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
admin = create(:administrator)
|
||||
|
||||
login_as(admin.user)
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
expect(page).to_not have_content "Comment as moderator"
|
||||
end
|
||||
end
|
||||
|
||||
feature 'Voting comments' do
|
||||
|
||||
background do
|
||||
@manuela = create(:user, verified_at: Time.current)
|
||||
@pablo = create(:user)
|
||||
@proposal = create(:proposal)
|
||||
@topic = create(:topic, community: @proposal.community)
|
||||
@comment = create(:comment, commentable: @topic)
|
||||
|
||||
login_as(@manuela)
|
||||
end
|
||||
|
||||
scenario 'Show' do
|
||||
create(:vote, voter: @manuela, votable: @comment, vote_flag: true)
|
||||
create(:vote, voter: @pablo, votable: @comment, vote_flag: false)
|
||||
|
||||
visit community_topic_path(@proposal.community, @topic)
|
||||
|
||||
within("#comment_#{@comment.id}_votes") do
|
||||
within(".in_favor") do
|
||||
expect(page).to have_content "1"
|
||||
end
|
||||
|
||||
within(".against") do
|
||||
expect(page).to have_content "1"
|
||||
end
|
||||
|
||||
expect(page).to have_content "2 votes"
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Create', :js do
|
||||
visit community_topic_path(@proposal.community, @topic)
|
||||
|
||||
within("#comment_#{@comment.id}_votes") do
|
||||
find(".in_favor a").click
|
||||
|
||||
within(".in_favor") do
|
||||
expect(page).to have_content "1"
|
||||
end
|
||||
|
||||
within(".against") do
|
||||
expect(page).to have_content "0"
|
||||
end
|
||||
|
||||
expect(page).to have_content "1 vote"
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Update', :js do
|
||||
visit community_topic_path(@proposal.community, @topic)
|
||||
|
||||
within("#comment_#{@comment.id}_votes") do
|
||||
find('.in_favor a').click
|
||||
find('.against a').click
|
||||
|
||||
within('.in_favor') do
|
||||
expect(page).to have_content "0"
|
||||
end
|
||||
|
||||
within('.against') do
|
||||
expect(page).to have_content "1"
|
||||
end
|
||||
|
||||
expect(page).to have_content "1 vote"
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Trying to vote multiple times', :js do
|
||||
visit community_topic_path(@proposal.community, @topic)
|
||||
|
||||
within("#comment_#{@comment.id}_votes") do
|
||||
find('.in_favor a').click
|
||||
find('.in_favor a').click
|
||||
|
||||
within('.in_favor') do
|
||||
expect(page).to have_content "1"
|
||||
end
|
||||
|
||||
within('.against') do
|
||||
expect(page).to have_content "0"
|
||||
end
|
||||
|
||||
expect(page).to have_content "1 vote"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
127
spec/features/communities_spec.rb
Normal file
@@ -0,0 +1,127 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Communities' do
|
||||
|
||||
background do
|
||||
Setting['feature.community'] = true
|
||||
end
|
||||
|
||||
after do
|
||||
Setting['feature.community'] = nil
|
||||
end
|
||||
|
||||
context 'Show' do
|
||||
|
||||
scenario 'Should display default content' do
|
||||
proposal = create(:proposal)
|
||||
community = proposal.community
|
||||
user = create(:user)
|
||||
login_as(user)
|
||||
|
||||
visit community_path(community)
|
||||
|
||||
expect(page).to have_content "Proposal community"
|
||||
expect(page).to have_content proposal.title
|
||||
expect(page).to have_content "Participate in the community of this proposal"
|
||||
expect(page).to have_link("Create topic", href: new_community_topic_path(community))
|
||||
expect(page).not_to have_selector(".button.disabled", text: "Create topic")
|
||||
end
|
||||
|
||||
scenario 'Should display disabled create topic button when user is not logged' do
|
||||
proposal = create(:proposal)
|
||||
community = proposal.community
|
||||
|
||||
visit community_path(community)
|
||||
|
||||
expect(page).to have_selector(".button.disabled", text: "Create topic")
|
||||
end
|
||||
|
||||
scenario 'Should display without_topics_text and participants when there are not topics' do
|
||||
proposal = create(:proposal)
|
||||
community = proposal.community
|
||||
|
||||
visit community_path(community)
|
||||
|
||||
expect(page).to have_content "Create the first community topic"
|
||||
expect(page).to have_content "Participants (1)"
|
||||
end
|
||||
|
||||
scenario 'Should display order selector and topic content when there are topics' do
|
||||
proposal = create(:proposal)
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
create(:comment, commentable: topic)
|
||||
|
||||
visit community_path(community)
|
||||
|
||||
expect(page).to have_selector ".wide-order-selector"
|
||||
within "#topic_#{topic.id}" do
|
||||
expect(page).to have_content topic.title
|
||||
expect(page).to have_content "#{topic.comments_count} comment"
|
||||
expect(page).to have_content I18n.l(topic.created_at.to_date)
|
||||
expect(page).to have_content topic.author.name
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Should display topic edit button when author is logged' do
|
||||
proposal = create(:proposal)
|
||||
community = proposal.community
|
||||
user = create(:user)
|
||||
topic1 = create(:topic, community: community, author: user)
|
||||
topic2 = create(:topic, community: community)
|
||||
login_as(user)
|
||||
|
||||
visit community_path(community)
|
||||
|
||||
within "#topic_#{topic1.id}" do
|
||||
expect(page).to have_link("Edit", href: edit_community_topic_path(community, topic1))
|
||||
end
|
||||
|
||||
within "#topic_#{topic2.id}" do
|
||||
expect(page).not_to have_link("Edit", href: edit_community_topic_path(community, topic2))
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Should display participant when there is topics' do
|
||||
proposal = create(:proposal)
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
|
||||
visit community_path(community)
|
||||
|
||||
within ".communities-participant" do
|
||||
expect(page).to have_content "Participants (2)"
|
||||
expect(page).to have_content topic.author.name
|
||||
expect(page).to have_content proposal.author.name
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Should display participants when there are topics and comments' do
|
||||
proposal = create(:proposal)
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
comment = create(:comment, commentable: topic)
|
||||
|
||||
visit community_path(community)
|
||||
|
||||
within ".communities-participant" do
|
||||
expect(page).to have_content "Participants (3)"
|
||||
expect(page).to have_content topic.author.name
|
||||
expect(page).to have_content comment.author.name
|
||||
expect(page).to have_content proposal.author.name
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Should redirect root path when communities are disabled' do
|
||||
Setting['feature.community'] = nil
|
||||
proposal = create(:proposal)
|
||||
community = proposal.community
|
||||
|
||||
visit community_path(community)
|
||||
|
||||
expect(current_path).to eq(root_path)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -89,6 +89,22 @@ feature 'Proposals' do
|
||||
expect(current_path).to_not eq(old_path)
|
||||
expect(current_path).to eq(right_path)
|
||||
end
|
||||
|
||||
scenario 'Can access the community' do
|
||||
Setting['feature.community'] = true
|
||||
|
||||
proposal = create(:proposal)
|
||||
visit proposal_path(proposal)
|
||||
expect(page).to have_content "Access the community"
|
||||
|
||||
Setting['feature.community'] = false
|
||||
end
|
||||
|
||||
scenario 'Can not access the community' do
|
||||
proposal = create(:proposal)
|
||||
visit proposal_path(proposal)
|
||||
expect(page).not_to have_content "Access the community"
|
||||
end
|
||||
end
|
||||
|
||||
context "Embedded video" do
|
||||
|
||||
102
spec/features/topics_specs.rb
Normal file
@@ -0,0 +1,102 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Topics' do
|
||||
|
||||
context 'New' do
|
||||
|
||||
scenario 'Should display disabled button to new topic page without user logged', :js do
|
||||
proposal = create(:proposal)
|
||||
community = proposal.community
|
||||
|
||||
visit community_path(community)
|
||||
|
||||
expect(page).to have_selector(".button.expanded.disabled")
|
||||
end
|
||||
|
||||
scenario 'Should can access to new topic page with user logged', :js do
|
||||
proposal = create(:proposal)
|
||||
community = proposal.community
|
||||
user = create(:user)
|
||||
login_as(user)
|
||||
visit community_path(community)
|
||||
|
||||
click_link "Create topic"
|
||||
|
||||
expect(page).to have_content "Create a topic"
|
||||
end
|
||||
|
||||
scenario 'Should have content on new topic page', :js do
|
||||
proposal = create(:proposal)
|
||||
community = proposal.community
|
||||
user = create(:user)
|
||||
login_as(user)
|
||||
visit community_path(community)
|
||||
|
||||
click_link "Create topic"
|
||||
|
||||
expect(page).to have_content "Topic Title"
|
||||
expect(page).to have_content "Description"
|
||||
expect(page).to have_content "Recommendations to create a topic"
|
||||
expect(page).to have_content "Do not write the topic title or whole sentences in capital letters. On the internet that is considered shouting. And no one likes to be yelled at."
|
||||
expect(page).to have_content "Any topic or comment that implies an illegal action will be eliminated, also those that intend to sabotage the spaces of the subject, everything else is allowed."
|
||||
expect(page).to have_content "Enjoy this space, the voices that fill it, it's yours too."
|
||||
expect(page).to have_button("Create topic")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'Create' do
|
||||
|
||||
scenario 'Should can create a new topic', :js do
|
||||
proposal = create(:proposal)
|
||||
community = proposal.community
|
||||
user = create(:user)
|
||||
login_as(user)
|
||||
|
||||
visit new_community_topic_path(community)
|
||||
fill_in "topic_title", with: "New topic title"
|
||||
fill_in "topic_description", with: "Topic description"
|
||||
click_button "Create topic"
|
||||
|
||||
expect(page).to have_content "New topic title"
|
||||
expect(current_path).to eq(community_path(community))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'Edit' do
|
||||
|
||||
scenario 'Should can edit a topic' do
|
||||
proposal = create(:proposal)
|
||||
community = proposal.community
|
||||
user = create(:user)
|
||||
topic = create(:topic, community: community, author: user)
|
||||
login_as(user)
|
||||
visit edit_community_topic_path(community, topic)
|
||||
|
||||
fill_in "topic_title", with: "Edit topic title"
|
||||
fill_in "topic_description", with: "Edit topic description"
|
||||
click_button "Edit topic"
|
||||
|
||||
expect(page).to have_content "Edit topic title"
|
||||
expect(current_path).to eq(community_path(community))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'Show' do
|
||||
|
||||
scenario 'Should can show topic' do
|
||||
proposal = create(:proposal)
|
||||
community = proposal.community
|
||||
topic = create(:topic, community: community)
|
||||
|
||||
visit community_topic_path(community, topic)
|
||||
|
||||
expect(page).to have_content community.proposal.title
|
||||
expect(page).to have_content topic.title
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
49
spec/lib/tasks/communities_spec.rb
Normal file
@@ -0,0 +1,49 @@
|
||||
require 'rails_helper'
|
||||
require 'rake'
|
||||
|
||||
describe 'Communities Rake' do
|
||||
|
||||
describe '#associate_community' do
|
||||
|
||||
before do
|
||||
Rake.application.rake_require "tasks/communities"
|
||||
Rake::Task.define_task(:environment)
|
||||
end
|
||||
|
||||
let :run_rake_task do
|
||||
Rake::Task['communities:associate_community'].reenable
|
||||
Rake.application.invoke_task 'communities:associate_community'
|
||||
end
|
||||
|
||||
context 'Associate community to Proposal' do
|
||||
|
||||
it 'When proposal has not community_id' do
|
||||
proposal = create(:proposal)
|
||||
proposal.update(community_id: nil)
|
||||
expect(proposal.community).to be_nil
|
||||
|
||||
run_rake_task
|
||||
proposal.reload
|
||||
|
||||
expect(proposal.community).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
context 'Associate community to Budget Investment' do
|
||||
|
||||
it 'When budget investment has not community_id' do
|
||||
investment = create(:budget_investment)
|
||||
investment.update(community_id: nil)
|
||||
expect(investment.community).to be_nil
|
||||
|
||||
run_rake_task
|
||||
investment.reload
|
||||
|
||||
expect(investment.community).to be_present
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
29
spec/models/community_spec.rb
Normal file
@@ -0,0 +1,29 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Community, type: :model do
|
||||
|
||||
it "should be valid when create proposal" do
|
||||
proposal = create(:proposal)
|
||||
|
||||
expect(proposal.community).to be_valid
|
||||
end
|
||||
|
||||
describe "#participants" do
|
||||
|
||||
it "should return participants without duplicates" do
|
||||
proposal = create(:proposal)
|
||||
community = proposal.community
|
||||
user1 = create(:user)
|
||||
user2 = create(:user)
|
||||
|
||||
topic1 = create(:topic, community: community, author: user1)
|
||||
create(:comment, commentable: topic1, author: user1)
|
||||
create(:comment, commentable: topic1, author: user2)
|
||||
topic2 = create(:topic, community: community, author: user2)
|
||||
|
||||
expect(community.participants).to include(user1)
|
||||
expect(community.participants).to include(user2)
|
||||
expect(community.participants).to include(proposal.author)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -62,6 +62,20 @@ describe :poll do
|
||||
end
|
||||
end
|
||||
|
||||
describe "#current_or_incoming" do
|
||||
it "returns current or incoming polls" do
|
||||
current = create(:poll, :current)
|
||||
incoming = create(:poll, :incoming)
|
||||
expired = create(:poll, :expired)
|
||||
|
||||
current_or_incoming = Poll.current_or_incoming
|
||||
|
||||
expect(current_or_incoming).to include(current)
|
||||
expect(current_or_incoming).to include(incoming)
|
||||
expect(current_or_incoming).to_not include(expired)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#document_has_voted?" do
|
||||
it "returns true if Poll::Voter with document exists" do
|
||||
poll = create(:poll)
|
||||
|
||||
61
spec/models/poll/shift_spec.rb
Normal file
@@ -0,0 +1,61 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe :shift do
|
||||
let(:shift) { build(:poll_shift) }
|
||||
|
||||
describe "validations" do
|
||||
|
||||
it "should be valid" do
|
||||
expect(shift).to be_valid
|
||||
end
|
||||
|
||||
it "should not be valid without a booth" do
|
||||
shift.booth = nil
|
||||
expect(shift).to_not be_valid
|
||||
end
|
||||
|
||||
it "should not be valid without an officer" do
|
||||
shift.officer = nil
|
||||
expect(shift).to_not be_valid
|
||||
end
|
||||
|
||||
it "should not be valid without a date" do
|
||||
shift.date = nil
|
||||
expect(shift).to_not be_valid
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "officer_assignments" do
|
||||
|
||||
it "should create corresponding officer_assignments" do
|
||||
poll1 = create(:poll)
|
||||
poll2 = create(:poll)
|
||||
poll3 = create(:poll)
|
||||
|
||||
booth = create(:poll_booth)
|
||||
officer = create(:poll_officer)
|
||||
|
||||
booth_assignment1 = create(:poll_booth_assignment, poll: poll1, booth: booth)
|
||||
booth_assignment2 = create(:poll_booth_assignment, poll: poll2, booth: booth)
|
||||
|
||||
shift = create(:poll_shift, booth: booth, officer: officer, date: Date.current)
|
||||
|
||||
officer_assignments = Poll::OfficerAssignment.all
|
||||
expect(officer_assignments.count).to eq(2)
|
||||
|
||||
oa1 = officer_assignments.first
|
||||
oa2 = officer_assignments.second
|
||||
|
||||
expect(oa1.officer).to eq(officer)
|
||||
expect(oa1.date).to eq(Date.current)
|
||||
expect(oa1.booth_assignment).to eq(booth_assignment1)
|
||||
|
||||
expect(oa2.officer).to eq(officer)
|
||||
expect(oa2.date).to eq(Date.current)
|
||||
expect(oa2.booth_assignment).to eq(booth_assignment2)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||