merge with master
This commit is contained in:
2
Gemfile
2
Gemfile
@@ -24,7 +24,7 @@ gem 'devise'
|
||||
gem 'omniauth'
|
||||
gem 'omniauth-twitter'
|
||||
gem 'omniauth-facebook', '~> 3.0.0'
|
||||
gem 'omniauth-google-oauth2', '~> 0.2.10'
|
||||
gem 'omniauth-google-oauth2', '~> 0.3.0'
|
||||
|
||||
gem 'kaminari'
|
||||
gem 'ancestry'
|
||||
|
||||
40
Gemfile.lock
40
Gemfile.lock
@@ -67,9 +67,9 @@ GEM
|
||||
arel (6.0.3)
|
||||
ast (2.2.0)
|
||||
bcrypt (3.1.10)
|
||||
browser (1.0.1)
|
||||
browser (1.1.0)
|
||||
builder (3.2.2)
|
||||
bullet (4.14.10)
|
||||
bullet (5.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.9.0)
|
||||
byebug (8.2.1)
|
||||
@@ -96,7 +96,7 @@ GEM
|
||||
rack-test (>= 0.5.4)
|
||||
xpath (~> 2.0)
|
||||
chronic (0.10.2)
|
||||
ckeditor (4.1.5)
|
||||
ckeditor (4.1.6)
|
||||
cocaine
|
||||
orm_adapter (~> 0.5.0)
|
||||
climate_control (0.0.3)
|
||||
@@ -173,7 +173,7 @@ GEM
|
||||
fuubar (2.0.0)
|
||||
rspec (~> 3.0)
|
||||
ruby-progressbar (~> 1.4)
|
||||
geocoder (1.2.13)
|
||||
geocoder (1.2.14)
|
||||
globalid (0.3.6)
|
||||
activesupport (>= 4.1.0)
|
||||
groupdate (2.5.0)
|
||||
@@ -229,7 +229,7 @@ GEM
|
||||
multipart-post (2.0.0)
|
||||
net-scp (1.2.1)
|
||||
net-ssh (>= 2.6.5)
|
||||
net-ssh (3.0.1)
|
||||
net-ssh (3.0.2)
|
||||
netrc (0.11.0)
|
||||
newrelic_rpm (3.14.1.311)
|
||||
nokogiri (1.6.7.1)
|
||||
@@ -247,23 +247,23 @@ GEM
|
||||
rack (>= 1.0, < 3)
|
||||
omniauth-facebook (3.0.0)
|
||||
omniauth-oauth2 (~> 1.2)
|
||||
omniauth-google-oauth2 (0.2.10)
|
||||
omniauth-google-oauth2 (0.3.0)
|
||||
addressable (~> 2.3)
|
||||
jwt (~> 1.0)
|
||||
multi_json (~> 1.3)
|
||||
omniauth (>= 1.1.1)
|
||||
omniauth-oauth2 (~> 1.3.1)
|
||||
omniauth-oauth2 (>= 1.3.1)
|
||||
omniauth-oauth (1.1.0)
|
||||
oauth
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (1.3.1)
|
||||
omniauth-oauth2 (1.4.0)
|
||||
oauth2 (~> 1.0)
|
||||
omniauth (~> 1.2)
|
||||
omniauth-twitter (1.2.1)
|
||||
json (~> 1.3)
|
||||
omniauth-oauth (~> 1.1)
|
||||
orm_adapter (0.5.0)
|
||||
paranoia (2.1.4)
|
||||
paranoia (2.1.5)
|
||||
activerecord (~> 4.0)
|
||||
parser (2.2.3.0)
|
||||
ast (>= 1.1, < 3.0)
|
||||
@@ -310,9 +310,9 @@ GEM
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
raindrops (0.15.0)
|
||||
rake (10.4.2)
|
||||
redcarpet (3.3.3)
|
||||
redcarpet (3.3.4)
|
||||
referer-parser (0.3.0)
|
||||
request_store (1.2.1)
|
||||
request_store (1.3.0)
|
||||
responders (2.1.1)
|
||||
railties (>= 4.2.0, < 5.1)
|
||||
rest-client (1.8.0)
|
||||
@@ -331,7 +331,7 @@ GEM
|
||||
rspec-expectations (3.4.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-mocks (3.4.0)
|
||||
rspec-mocks (3.4.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-rails (3.4.0)
|
||||
@@ -344,14 +344,14 @@ GEM
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-support (3.4.1)
|
||||
ruby-progressbar (1.7.5)
|
||||
sass (3.4.20)
|
||||
sass (3.4.21)
|
||||
sass-rails (5.0.4)
|
||||
railties (>= 4.0.0, < 5.0)
|
||||
sass (~> 3.1)
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
sprockets-rails (>= 2.0, < 4.0)
|
||||
tilt (>= 1.1, < 3)
|
||||
sassc (1.8.2)
|
||||
sassc (1.8.3)
|
||||
bundler
|
||||
ffi (~> 1.9.6)
|
||||
sass (>= 3.3.0)
|
||||
@@ -369,14 +369,14 @@ GEM
|
||||
nokogiri (>= 1.4.0)
|
||||
nori (~> 2.4)
|
||||
wasabi (~> 3.4)
|
||||
simple_captcha2 (0.3.4)
|
||||
simple_captcha2 (0.4.0)
|
||||
rails (>= 4.1)
|
||||
simplecov (0.11.1)
|
||||
docile (~> 1.1.0)
|
||||
json (~> 1.8)
|
||||
simplecov-html (~> 0.10.0)
|
||||
simplecov-html (0.10.0)
|
||||
spring (1.6.1)
|
||||
spring (1.6.2)
|
||||
spring-commands-rspec (1.0.4)
|
||||
spring (>= 0.9.1)
|
||||
sprockets (3.5.2)
|
||||
@@ -395,11 +395,11 @@ GEM
|
||||
thor (0.19.1)
|
||||
thread (0.2.2)
|
||||
thread_safe (0.3.5)
|
||||
tilt (2.0.1)
|
||||
tilt (2.0.2)
|
||||
tins (1.6.0)
|
||||
turbolinks (2.5.3)
|
||||
coffee-rails
|
||||
turnout (2.2.0)
|
||||
turnout (2.2.1)
|
||||
rack (~> 1.3)
|
||||
rack-accept (~> 0.4)
|
||||
tzinfo (1.2.2)
|
||||
@@ -477,7 +477,7 @@ DEPENDENCIES
|
||||
newrelic_rpm (~> 3.14)
|
||||
omniauth
|
||||
omniauth-facebook (~> 3.0.0)
|
||||
omniauth-google-oauth2 (~> 0.2.10)
|
||||
omniauth-google-oauth2 (~> 0.3.0)
|
||||
omniauth-twitter
|
||||
paranoia
|
||||
pg
|
||||
@@ -504,4 +504,4 @@ DEPENDENCIES
|
||||
whenever
|
||||
|
||||
BUNDLED WITH
|
||||
1.10.6
|
||||
1.11.2
|
||||
|
||||
Binary file not shown.
@@ -19,7 +19,6 @@
|
||||
<glyph glyph-name="like" unicode="k" d="M91 128c0 5-1 9-5 13-4 3-8 5-13 5-5 0-9-2-13-5-3-4-5-8-5-13 0-5 2-9 5-13 4-4 8-5 13-5 5 0 9 1 13 5 4 4 5 8 5 13z m46 146l0-183c0-5-2-9-5-12-4-4-8-6-13-6l-82 0c-5 0-10 2-13 6-4 3-6 7-6 12l0 183c0 5 2 10 6 13 3 4 8 6 13 6l82 0c5 0 9-2 13-6 3-3 5-8 5-13z m338 0c0-16-5-30-15-42 3-9 4-16 4-22 1-14-4-28-12-39 3-11 3-22 0-34-3-10-8-19-16-26 2-22-3-39-14-52-12-15-31-22-56-22l-37 0c-12 0-26 1-41 4-15 3-26 6-35 8-8 3-19 7-34 12-24 8-39 12-45 12-5 0-10 2-13 6-4 3-6 7-6 12l0 184c0 4 2 8 6 12 3 4 7 5 12 6 4 0 12 6 22 17 9 11 19 22 28 34 13 17 23 28 29 35 4 3 7 8 9 13 3 6 4 11 5 14 1 4 2 9 4 17 1 8 3 14 4 18 1 4 2 9 5 15 3 5 6 10 10 14 3 4 8 5 13 5 8 0 16-1 23-3 7-2 13-4 17-7 5-3 9-7 12-12 3-4 5-9 7-12 1-4 2-9 3-15 1-5 1-10 2-13 0-2 0-6 0-11 0-7-1-14-3-21-2-8-4-13-5-18-2-4-5-9-8-16-1-1-2-2-3-5-1-2-3-4-3-6-1-2-2-4-3-7l80 0c14 0 27-5 38-16 11-11 16-24 16-39z"/>
|
||||
<glyph glyph-name="check" unicode="l" d="M477 350c0-7-2-14-8-19l-206-207-39-39c-6-5-12-8-20-8-7 0-14 3-19 8l-142 142c-6 6-8 12-8 20 0 7 2 14 8 19l38 39c6 5 12 8 20 8 7 0 14-3 19-8l84-84 188 188c5 5 12 8 19 8 8 0 14-3 20-8l38-39c6-6 8-12 8-20z"/>
|
||||
<glyph glyph-name="edit" unicode="m" d="M140 73l26 26-67 67-26-26 0-30 37 0 0-37z m150 265c0 4-2 7-7 7-1 0-3-1-4-2l-155-155c-2-2-2-3-2-5 0-4 2-6 6-6 2 0 4 0 5 2l155 154c1 2 2 3 2 5z m-16 55l119-119-238-237-118 0 0 118z m195-27c0-10-3-19-10-26l-48-47-118 118 47 48c7 7 15 10 26 10 10 0 18-3 26-10l67-67c7-8 10-16 10-26z"/>
|
||||
<glyph glyph-name="star" unicode="n" d="M494 327c0-4-3-9-8-14l-103-101 24-143c0-1 0-3 0-5 0-4-1-8-3-10-2-3-4-5-8-5-4 0-8 2-12 4l-128 67-128-67c-4-2-8-4-12-4-4 0-7 2-9 5-2 2-3 6-3 10 0 1 0 3 1 5l24 143-104 101c-4 6-7 10-7 14 0 7 6 12 16 13l144 21 64 130c4 8 8 12 14 12 6 0 10-4 14-12l64-130 144-21c10-1 16-6 16-13z"/>
|
||||
<glyph glyph-name="user" unicode="o" d="M410 203l-80 38-34 16c15 9 27 24 35 41 6 14 10 29 10 46 0 9-1 18-4 27-10 41-42 72-81 72-38 0-70-30-81-70-2-9-4-19-4-29 0-18 4-34 11-49 8-16 20-30 35-39l-32-15-83-38c-7-4-12-12-12-21l0-91c0-12 8-22 19-22l294 0c11 0 19 10 19 22l0 91c0 9-4 17-12 21z"/>
|
||||
<glyph glyph-name="settings" unicode="q" d="M329 256c0 20-7 37-21 52-15 14-32 21-52 21-20 0-37-7-52-21-14-15-21-32-21-52 0-20 7-37 21-52 15-14 32-21 52-21 20 0 37 7 52 21 14 15 21 32 21 52z m146 31l0-63c0-3 0-5-2-7-1-2-3-3-6-4l-52-8c-4-10-8-19-12-26 7-9 17-22 31-39 2-2 3-5 3-7 0-3-1-5-3-7-5-7-14-17-28-31-14-13-23-20-27-20-2 0-5 1-7 3l-40 31c-8-5-17-8-26-11-3-26-6-44-8-53-1-6-5-8-10-8l-64 0c-2 0-5 0-7 2-2 2-3 4-3 6l-8 53c-9 3-18 6-26 10l-40-30c-2-2-4-3-7-3-3 0-5 1-7 3-24 22-40 38-47 48-2 2-2 4-2 7 0 2 0 4 2 6 3 4 8 11 14 19 7 9 12 16 16 21-5 9-9 19-12 28l-52 8c-3 0-5 1-6 3-2 2-2 4-2 7l0 63c0 3 0 5 2 7 1 2 3 3 5 4l53 8c3 8 7 17 12 26-8 11-18 24-31 39-2 3-3 5-3 7 0 2 1 4 3 7 5 7 14 17 28 30 14 14 23 21 27 21 2 0 5-1 7-3l40-31c8 5 17 8 26 11 3 26 6 44 8 53 1 6 5 8 10 8l64 0c2 0 5 0 7-2 2-2 3-4 3-6l8-53c9-3 18-6 26-10l40 30c2 2 4 3 7 3 3 0 5-1 7-3 25-23 41-39 47-49 2-1 2-3 2-6 0-2 0-4-2-6-3-4-8-11-14-19-7-9-12-16-16-21 5-9 9-18 12-28l52-8c3 0 5-1 6-3 2-2 2-4 2-7z"/>
|
||||
<glyph glyph-name="stats" unicode="r" d="M17 222c-14 4-20 13-16 29 3 14 12 20 27 16 0 0 50-12 50-12 0 0-26-41-26-41 0 0-35 8-35 8m455-6c4 4 10 6 16 6 7-1 12-3 16-8 11-11 11-22-1-33 0 0-128-115-128-115-5-4-10-6-16-6-5 0-9 2-14 5 0 0-146 112-146 112 0 0-28 8-28 8 0 0 26 40 26 40 0 0 18-4 18-4 4-1 7-2 8-4 0 0 135-104 135-104 0 0 114 103 114 103m-251 112c0 0-178-280-178-280-4-8-11-12-20-12-4 0-8 2-12 5-5 3-9 8-10 14-1 7 0 12 3 17 0 0 191 300 191 300 3 6 7 9 14 11 6 2 12 1 19-3 0 0 125-80 125-80 0 0 115 166 115 166 4 6 9 9 15 10 6 1 12-1 17-5 13-8 15-18 6-31 0 0-128-185-128-185-9-12-19-14-32-6 0 0-125 79-125 79"/>
|
||||
@@ -30,12 +29,10 @@
|
||||
<glyph glyph-name="eye" unicode="p" d="M475 238c-29 45-65 78-108 101 11-20 17-42 17-65 0-35-13-65-38-90-25-25-55-38-90-38-35 0-65 13-90 38-25 25-38 55-38 90 0 23 6 45 17 65-43-23-79-56-108-101 25-39 57-70 95-94 38-23 79-34 124-34 45 0 86 11 124 34 38 24 70 55 95 94z m-205 109c0 4-2 7-4 10-3 3-6 4-10 4-24 0-44-8-61-25-17-17-26-38-26-62 0-4 1-7 4-9 3-3 6-4 10-4 4 0 7 1 10 4 2 2 4 5 4 9 0 17 5 31 17 42 12 12 26 18 42 18 4 0 7 1 10 4 2 2 4 6 4 9z m242-109c0-7-2-13-6-20-26-44-62-79-107-105-45-27-93-40-143-40-50 0-98 13-143 40-45 26-81 61-107 105-4 7-6 13-6 20 0 6 2 13 6 19 26 44 62 79 107 106 45 26 93 39 143 39 50 0 98-13 143-39 45-27 81-62 107-106 4-6 6-13 6-19z"/>
|
||||
<glyph glyph-name="x" unicode="v" d="M426 134c0-7-3-14-8-19l-39-39c-5-5-12-8-20-8-7 0-14 3-19 8l-84 84-84-84c-5-5-12-8-19-8-8 0-15 3-20 8l-39 39c-5 5-8 12-8 19 0 8 3 14 8 20l84 84-84 84c-5 5-8 12-8 19 0 8 3 14 8 20l39 38c5 6 12 8 20 8 7 0 14-2 19-8l84-84 84 84c5 6 12 8 19 8 8 0 15-2 20-8l39-38c5-6 8-12 8-20 0-7-3-14-8-19l-84-84 84-84c5-6 8-12 8-20z"/>
|
||||
<glyph glyph-name="flag" unicode="w" d="M434 389c-1 0-2 0-3 0l0 0c-17-9-37-14-58-14-38 0-73 17-95 45-21 19-49 31-80 31-29 0-56-11-77-29-4 9-13 15-24 15-15 0-27-12-27-27l0-322c0-15 12-27 27-27 15 0 27 12 27 27l0 145c17 9 36 13 56 13 39 0 73-17 96-45 21-19 49-31 79-31 33 0 63 14 84 36 2 2 3 4 3 6l0 169c0 5-4 8-8 8z"/>
|
||||
<glyph glyph-name="notification" unicode="x" d="M261 27c0 3-2 5-5 5-11 0-21 4-29 12-8 8-12 18-12 29 0 3-2 5-5 5-3 0-4-2-4-5 0-14 5-26 14-35 10-10 22-15 36-15 3 0 5 1 5 4z m-190 83l370 0c-31 34-54 73-70 117-16 44-24 90-24 139 0 48-30 73-91 73-61 0-91-25-91-73 0-49-8-95-24-139-16-44-39-83-70-117z m423 0c0-10-4-19-11-26-7-7-16-11-26-11l-128 0c0-20-7-37-21-52-15-14-32-21-52-21-20 0-37 7-52 21-14 15-21 32-21 52l-128 0c-10 0-19 4-26 11-7 7-11 16-11 26 36 30 64 68 82 113 19 45 28 93 28 143 0 31 9 56 27 75 19 18 44 29 76 33-2 3-2 7-2 11 0 7 2 14 8 19 5 5 11 8 19 8 8 0 14-3 19-8 6-5 8-12 8-19 0-4 0-8-2-11 32-4 57-15 76-33 18-19 27-44 27-75 0-50 9-98 28-143 18-45 46-83 82-113z"/>
|
||||
<glyph glyph-name="comment" unicode="y" d="M256 402c-39 0-75-6-109-20-34-13-61-31-81-53-19-23-29-47-29-73 0-21 6-42 20-61 14-19 33-36 58-50l24-14-7-28c-5-17-12-34-20-49 29 12 55 28 78 49l13 11 16-2c13-2 25-2 37-2 39 0 75 6 109 20 34 13 61 31 81 53 19 23 29 47 29 73 0 26-10 50-29 73-20 22-47 40-81 53-34 14-70 20-109 20z m256-146c0-33-11-64-34-92-23-28-54-50-93-66-40-17-83-25-129-25-13 0-27 1-41 2-38-33-82-56-132-69-9-2-20-4-32-6l-2 0c-3 0-5 1-8 3-2 2-3 5-4 8l0 0c-1 1-1 2 0 4 0 1 0 2 0 2 0 1 1 2 2 3l1 3c0 0 1 1 2 2 2 2 2 3 3 3 1 1 4 5 8 10 5 5 8 8 10 10 2 3 5 6 9 12 4 5 7 10 9 14 3 5 5 10 8 17 3 7 5 14 8 22-30 17-54 38-71 63-17 25-26 51-26 80 0 33 11 64 34 92 23 28 54 50 93 66 40 17 83 25 129 25 46 0 89-8 129-25 39-16 70-38 93-66 23-28 34-59 34-92z"/>
|
||||
<glyph glyph-name="reply" unicode="z" d="M183 203l0-20c0-8-4-14-11-17-3-1-5-1-7-1-6 0-10 1-13 5l-147 146c-3 4-5 8-5 13 0 5 2 9 5 13l147 146c5 6 12 8 20 4 7-3 11-9 11-17l0-19-114-114c-3-4-5-8-5-13 0-5 2-9 5-13z m329-11c0-11-2-24-5-38-3-15-7-28-11-40-4-11-9-23-14-35-5-12-8-21-11-26l-6-12c-1-3-4-4-8-4-1 0-2 0-2 0-5 1-7 5-7 10 8 76-2 130-30 161-12 14-29 24-49 32-20 7-46 12-76 15l0-72c0-8-4-14-12-17-2-1-4-1-7-1-5 0-9 1-13 5l-146 146c-3 4-5 8-5 13 0 5 2 9 5 13l146 146c6 6 13 8 20 4 8-3 12-9 12-17l0-74c78-6 135-27 171-64 32-33 48-81 48-145z"/>
|
||||
<glyph glyph-name="facebook" unicode="A" d="M292 353l74 0-9-81-65 0 0-235-97 0 0 235-49 0 0 81 49 0 0 49c0 35 8 61 24 79 17 18 44 26 81 26l65 0 0-81-40 0c-8 0-14 0-18-2-5-1-8-3-10-6-2-4-3-7-4-10 0-3-1-8-1-14z"/>
|
||||
<glyph glyph-name="google-plus" unicode="B" d="M269 93c0 4-1 8-2 12-1 4-1 7-2 10-1 3-3 7-5 10-3 4-5 6-6 9-2 2-5 5-8 8-3 4-6 6-8 8-2 1-5 4-9 7-4 3-7 5-9 6-1 2-5 4-9 7-5 3-8 5-9 6-3 0-8 1-14 1-11 0-21-1-31-2-9-2-20-4-30-8-11-3-20-7-28-13-8-5-15-12-20-21-5-9-8-19-8-31 0-13 4-24 10-34 7-11 16-19 27-24 11-6 22-11 34-13 12-3 24-5 37-5 11 0 22 1 32 4 10 2 19 6 28 11 9 5 16 12 22 21 5 9 8 19 8 31z m-35 247c0 11-1 23-4 36-4 13-8 25-14 37-6 12-14 22-24 30-10 8-21 12-34 12-18 0-31-7-41-20-10-13-15-29-15-47 0-9 1-18 4-28 2-10 5-20 10-30 4-10 10-19 16-27 6-8 13-14 22-19 9-5 18-7 28-7 18 0 32 5 40 17 8 11 12 27 12 46z m-37 135l125 0-39-22-38 0c13-9 24-21 31-36 7-16 11-32 11-48 0-15-2-27-6-38-5-11-10-20-16-26-7-7-13-13-19-19-7-5-12-11-16-17-5-6-7-13-7-20 0-5 2-9 5-14 3-5 7-9 12-14 5-4 11-9 17-14 6-4 12-10 18-15 6-6 12-13 17-19 5-7 9-15 12-25 3-9 5-19 5-30 0-30-13-57-40-81-29-25-69-37-120-37-11 0-23 1-34 3-12 2-23 5-35 9-12 5-22 10-31 17-9 7-16 15-22 25-6 11-9 22-9 35 0 12 4 25 11 39 6 12 15 22 27 31 12 9 26 16 42 21 15 4 30 8 44 10 14 2 28 3 43 4-12 16-18 30-18 42 0 3 0 5 0 7 1 2 1 4 2 6 0 1 1 3 2 6 1 2 1 4 2 6-8-1-14-2-20-2-29 0-53 10-73 28-20 19-31 43-31 71 0 26 9 50 28 71 18 21 40 35 66 41 18 4 36 5 54 5z m297-73l0-36-73 0 0-73-37 0 0 73-73 0 0 36 73 0 0 73 37 0 0-73z"/>
|
||||
<glyph glyph-name="language" unicode="C" d="M256 475c40 0 77-9 110-29 34-20 60-46 80-80 20-33 29-70 29-110 0-40-9-77-29-110-20-34-46-60-80-80-33-20-70-29-110-29-40 0-77 9-110 29-34 20-60 46-80 80-20 33-29 70-29 110 0 40 9 77 29 110 20 34 46 60 80 80 33 20 70 29 110 29z m78-148c0-1-1-2-2-3-2-2-3-3-4-3 0 0 1 1 1 2 0 1 1 2 1 3 1 1 1 2 1 2 2 1 4 2 7 4 2 1 7 2 15 3 6 2 11 1 14-3 0 1 1 2 3 4 2 2 3 3 4 3 1 1 2 1 4 2 3 0 4 1 5 2l0 6c-2 0-4 1-5 2-1 2-2 4-2 6 0 0 0-1-1-2 0 1-1 2-2 2-1 0-2 0-3 0-1-1-2-1-3 0-1 0-3 1-4 2-1 1-2 2-2 4-1 3-1 4-1 5-1 1-2 2-3 3-1 1-2 2-3 3 0 0 0 1 0 1-1 1-1 2-1 2-1 1-1 1-1 2-1 0-1 0-2 0-1 0-1 0-2-1-1-1-1-2-2-3-1-1-1-1-1-1-1 0-2 0-2 0-1 0-1 0-1 0-1 0-1-1-2-1 0 0-1-1-1-1-1 0-2-1-3-1-1 0-1 0-2 0 3 1 3 2 0 3-2 0-4 1-5 1 2 0 3 1 2 3 0 2-1 3-2 4l1 0c0 1-1 2-2 2-2 1-3 2-5 3-2 1-3 1-4 2-1 1-5 1-10 2-5 1-8 1-9 0-1-1-1-2-1-3 0 0 0-2 1-4 1-1 1-3 1-3 0-1 0-3-2-4-1-1-2-2-2-3 0-2 2-3 4-5 3-1 4-3 3-6 0-1-2-3-4-4-3-2-4-3-5-4-1-1-1-3 0-5 0-2 1-4 3-5 0 0 0-1 0-1 0 0 0-1-1-1 0-1-1-1-1-1-1-1-2-1-2-1l-1-1c-2-1-4 0-6 2-2 2-3 4-4 7-1 5-3 8-4 9-5 1-8 1-9-1-1 3-5 5-11 8-5 2-11 2-17 1 1 0 1 2 0 4-1 3-3 4-5 4 0 1 1 3 1 5 0 2 0 3 0 4 1 2 2 4 3 6 1 0 1 1 2 3 2 1 2 2 3 3 1 2 1 2 0 2 7-1 12 0 15 3 1 1 2 3 3 5 1 2 2 4 3 5 2 1 3 2 4 2 1-1 2-1 4-2 2-1 3-1 4-1 3-1 4 0 5 3 0 2-1 4-3 5 3 0 3 2 1 5-1 2-1 2-2 3-2 1-5 0-8-2-1 0-1-1 1-2 0 0-1-1-3-3-1-2-3-4-5-5-1-1-3-1-4 2 0 0-1 1-2 3-1 3-1 4-2 4-2 0-3-1-5-4 1 2 0 3-3 4-3 2-5 2-7 3 4 2 3 4-2 7-2 1-4 2-6 2-3 0-5 0-6-1-1-2-1-3-1-4 0-1 0-1 1-2 1-1 2-1 3-2 1 0 2 0 3-1 2 0 2 0 3-1 3-1 3-3 2-4 0 0-1 0-2-1-2 0-3 0-4-1-1 0-1-1-1-1-1-1-1-2 0-4 0-2 0-3-1-4-1 1-2 3-2 5-1 2-2 4-2 5 1-2-1-3-8-2l-2 0c-1 0-3 0-5 0-2-1-4-1-6-1-1 1-3 1-4 3 0 1 0 3 0 5 0 1 1 1 1 1 0 1-1 1-3 3-1 1-2 2-3 2-8-3-17-7-26-12 1 0 2 0 3 1 1 0 2 1 4 2 1 0 2 1 3 1 6 3 10 3 12 2l1 2c3-3 5-6 6-8-2 1-4 1-9 1-4-1-6-3-6-4 1-2 2-4 1-5 0 1-2 2-3 3-1 1-3 2-4 3-1 1-3 1-4 2-3 0-6-1-7-1-28-15-50-36-67-63 1-1 3-2 4-2 0-1 1-1 1-3 0-2 0-3 1-3 0-1 1 0 3 1 2-2 2-4 1-6 0 0 4-2 12-7 4-4 6-6 6-6 1-3 0-4-2-6-1 1-1 2-3 3-2 1-2 2-3 1 0-1 0-3 1-5 0-3 1-4 3-4-2 0-3-1-3-4-1-3-1-7-1-10 0-4 0-6 0-7l0 0c0-3 0-6 2-10 2-5 4-6 6-6-2 0 0-5 6-12 1-2 2-3 2-3 1 0 2-1 4-2 1-1 3-2 4-3 1-1 2-2 3-3 0-1 1-3 3-6 1-3 2-6 4-7-1-1 0-3 2-6 2-2 3-4 3-6 0 0 0 0 0 0-1-1-1-1-1-1 0-1 2-2 4-4 3-1 4-2 5-3 0-1 0-2 0-3 0-2 1-3 1-3 1-1 1-1 2-1 1 4-1 10-6 18-3 4-5 7-5 8-1 1-1 2-2 4 0 2-1 4-1 5 0 0 1-1 2-1 0 0 1 0 2-1 1 0 2-1 2-1 1 0 1-1 1-1-1-1-1-3 0-5 1-2 2-4 4-5 1-2 3-3 5-6 1-2 3-3 3-3 1-1 2-3 4-6 2-2 2-4 0-4 2 0 4-1 6-3 2-1 3-3 5-5 1-2 1-4 2-8 0-3 1-5 1-7 1-1 1-2 3-3 1-2 2-3 3-3l5-2c0 0 1-1 4-2 1-1 2-2 5-3 2-2 4-3 6-4 2 0 3-1 5-1 1 0 2 0 4 1 1 0 3 1 4 1 2 0 5-1 8-4 3-4 5-6 6-6 7-4 12-5 16-4-1 0-1 0 0-2 0-1 1-2 2-4 1-2 2-3 3-4 0-1 1-2 1-3 1-1 3-2 5-4 3-2 4-3 5-4 2 0 2 1 2 2 0-1 1-3 2-5 2-3 4-4 6-3 2 0 4 3 4 9-6-3-11-1-14 5 0 0-1 1-1 2-1 0-1 1-1 2-1 1-1 2-1 2 0 1 0 2 0 3 0 0 1 0 1 0 2 0 3 1 3 1 0 1 0 2 0 4-1 2-1 3-1 4-1 1-2 3-4 5-1 3-3 4-3 5-1-2-2-3-5-3-2 1-3 1-4 3 0 0 0-1-1-2 0 0 0-1 0-1-2 0-4 0-4 0 0 0 0 2 0 5 1 3 1 5 1 6 1 1 1 2 2 4 1 1 2 3 2 4 1 1 1 2 1 3 0 2 0 2-1 3-1 1-3 1-5 1-4 0-6-2-7-6-1 0-1-1-1-3-1-1-1-2-2-3 0-1-1-2-2-2-2-1-4-1-7-1-3 0-6 1-7 2-2 1-5 4-6 8-2 4-3 8-3 11 0 1 0 4 1 7 0 3 0 6 0 7 1 2 0 4-1 7 0 1 1 2 2 3 2 1 3 2 3 3 1 0 1 0 2 0 0 1 0 1 1 0 0 0 1 0 1 1 0 0 1 1 1 2 0 0-1 0-1 0-1 1-1 1-1 1 1 0 4 0 8 1 4 1 6 0 8-1 2-2 5-2 6 1 0 0 0 1-1 3 0 1 0 2 0 3 1-5 4-6 8-2 1-1 2-1 5-2 2 0 4 0 5-1 0 0 1-1 2-2 0 0 1-1 1-1 1 0 1 0 2 0 0 1 1 1 2 2 2-3 3-5 4-7 2-7 3-12 5-12 1-1 2-1 3-1 1 0 1 1 1 3 1 1 1 3 0 4 0 1 0 2 0 3l0 3 0 5-1 2c-2 1-4 2-5 4-1 1 0 3 1 5 1 2 2 3 4 5 0 0 1 1 2 1 1 1 3 1 5 2 1 1 2 2 3 2 4 4 6 7 4 10 2 0 3 1 4 3-1 0-1 0-2 1-1 0-1 1-2 1-1 1-1 1-1 1 1 1 2 2 0 4 1 1 2 2 2 3 1 2 2 3 3 3 1-2 3-2 6 0 1 1 1 3 0 4 1 2 3 3 6 3 3 1 4 2 5 3 1 0 2 0 2 1 0 0 1 1 1 3 0 2 0 3 0 3 1 1 3 2 5 3 2 1 3 1 3 1l5 4c1 0 1 1 0 1 4-1 7 0 9 3 2 2 1 4-2 6 1 1 1 2 0 2-2 1-3 1-5 2 1 0 2 0 4 0 1 0 2 0 3 0 2 2 2 4-2 5-4 1-8 0-13-3z m-46-251c39 7 72 25 100 54-1 1-2 1-4 1-1 1-3 1-3 1-4 2-6 2-7 3 0 1 0 2-1 3 0 1-1 2-2 3-1 0-2 1-4 2-1 1-2 2-3 2 0 1-1 1-2 2-1 1-1 1-2 1 0 1-1 1-2 2-1 0-2 0-2 0-1 0-2 0-3 0l-1 0c-1 0-1-1-2-1 0 0-1-1-1-1-1 0-1 0-1-1 0 0 0 0 0 0-4 3-8 5-11 6-1 0-2 1-3 1-1 1-2 2-3 2-1 1-2 1-3 1-1 0-2-1-3-2-1-1-1-3-2-4 0-2 0-4 0-4-1 1-1 2 0 5 1 2 1 4 0 5 0 1-1 2-3 1-1 0-2 0-3-1-1 0-2-1-3-2-2-1-2-2-3-2 0 0-1-1-2-2-2-1-2-1-3-2 0-1-1-2-1-3-1-2-1-3-2-3 0 0-1 1-3 1-2 1-3 1-3 2 1-2 1-5 1-10 1-5 1-8 2-11 1-6 0-10-4-14-5-4-8-8-8-11-1-4 0-7 3-7 0-2 0-4-2-6-1-3-2-5-2-6 0-2 0-3 1-5z"/>
|
||||
<glyph glyph-name="search" unicode="E" d="M347 274c0 36-12 66-37 91-25 25-55 37-91 37-35 0-65-12-90-37-25-25-38-55-38-91 0-35 13-65 38-90 25-25 55-38 90-38 36 0 66 13 91 38 25 25 37 55 37 90z m147-237c0-10-4-19-11-26-7-7-16-11-26-11-10 0-19 4-26 11l-98 98c-34-24-72-36-114-36-27 0-53 5-78 16-25 11-46 25-64 43-18 18-32 39-43 64-10 25-16 51-16 78 0 28 6 54 16 78 11 25 25 47 43 65 18 18 39 32 64 43 25 10 51 15 78 15 28 0 54-5 79-15 24-11 46-25 64-43 18-18 32-40 43-65 10-24 16-50 16-78 0-42-12-80-36-114l98-98c7-7 11-15 11-25z"/>
|
||||
<glyph glyph-name="external" unicode="F" d="M402 247l0-92c0-22-8-42-24-58-16-16-35-24-58-24l-238 0c-22 0-42 8-58 24-16 16-24 36-24 58l0 238c0 23 8 42 24 58 16 16 36 24 58 24l201 0c3 0 5 0 7-2 2-2 3-4 3-7l0-18c0-3-1-5-3-7-2-1-4-2-7-2l-201 0c-12 0-23-5-32-14-9-9-13-19-13-32l0-238c0-12 4-23 13-32 9-9 20-13 32-13l238 0c13 0 23 4 32 13 9 9 14 20 14 32l0 92c0 3 1 5 2 6 2 2 4 3 7 3l18 0c3 0 5-1 7-3 1-1 2-3 2-6z m110 247l0-147c0-5-2-9-5-12-4-4-8-6-13-6-5 0-10 2-13 6l-50 50-187-186c-2-2-4-3-6-3-3 0-5 1-7 3l-32 32c-2 2-3 4-3 7 0 2 1 4 3 6l186 187-50 50c-4 3-6 8-6 13 0 5 2 9 6 13 3 3 7 5 12 5l147 0c5 0 9-2 13-5 3-4 5-8 5-13z"/>
|
||||
<glyph glyph-name="video" unicode="D" d="M438 99c14 0 25 11 25 26l0 262c0 15-11 26-25 26l-364 0c-14 0-25-11-25-26l0-262c0-15 11-26 25-26z m-26 51l-312 0 0 212 312 0z m-80 105l-61-36-62-35 0 141 62-35z"/>
|
||||
@@ -45,4 +42,8 @@
|
||||
<glyph glyph-name="box" unicode="I" d="M311 274c0 5-2 10-6 13-3 4-7 6-12 6l-74 0c-5 0-9-2-12-6-4-3-6-8-6-13 0-5 2-9 6-13 3-3 7-5 12-5l74 0c5 0 9 2 12 5 4 4 6 8 6 13z m164 55l0-274c0-5-1-9-5-13-4-4-8-5-13-5l-402 0c-5 0-9 1-13 5-4 4-5 8-5 13l0 274c0 5 1 9 5 13 4 4 8 5 13 5l402 0c5 0 9-1 13-5 4-4 5-8 5-13z m19 128l0-73c0-5-2-9-6-13-3-3-8-5-13-5l-438 0c-5 0-10 2-13 5-4 4-6 8-6 13l0 73c0 5 2 9 6 13 3 4 8 5 13 5l438 0c5 0 10-1 13-5 4-4 6-8 6-13z"/>
|
||||
<glyph glyph-name="youtube" unicode="K" d="M314 157l0-61c0-12-4-19-11-19-5 0-9 2-13 6l0 86c4 5 8 7 13 7 7 0 11-7 11-19z m97-1l0-13-26 0 0 13c0 13 4 20 13 20 8 0 13-7 13-20z m-276 63l30 0 0 26-89 0 0-26 30 0 0-163 29 0z m82-163l25 0 0 141-25 0 0-108c-6-8-11-12-16-12-4 0-6 2-6 6-1 1-1 4-1 10l0 104-25 0 0-112c0-9 1-16 2-20 2-7 8-11 17-11 9 0 19 6 29 17z m122 42l0 57c0 13 0 23-2 28-3 11-10 16-20 16-10 0-19-5-27-16l0 62-25 0 0-189 25 0 0 14c9-11 17-16 27-16 10 0 17 5 20 16 2 5 2 14 2 28z m97 3l0 4-26 0c0-10 0-16-1-18-1-6-5-10-11-10-9 0-13 7-13 20l0 25 51 0 0 29c0 15-3 26-8 33-7 10-17 15-30 15-13 0-23-5-31-15-5-7-8-18-8-33l0-49c0-15 3-26 9-33 7-10 17-15 31-15 13 0 24 5 30 15 4 5 6 10 6 16 1 1 1 7 1 16z m-174 261l0 60c0 13-4 20-12 20-8 0-12-7-12-20l0-60c0-13 4-20 12-20 8 0 12 7 12 20z m206-215c0-44-3-77-8-100-2-11-8-20-16-28-9-7-18-12-29-13-35-4-88-6-159-6-71 0-124 2-159 6-11 1-20 6-29 13-8 8-14 17-16 28-5 22-8 55-8 100 0 45 3 78 8 100 2 12 8 21 16 29 9 7 18 12 30 13 35 4 87 6 158 6 71 0 124-2 159-6 11-1 20-6 29-13 8-8 14-17 16-29 5-21 8-54 8-100z m-285 365l29 0-35-114 0-77-28 0 0 77c-3 14-9 34-18 61-7 19-13 37-18 53l30 0 20-75z m105-95l0-50c0-16-2-27-8-34-7-10-17-14-30-14-13 0-23 4-30 14-5 7-8 19-8 34l0 50c0 15 3 26 8 33 7 10 17 15 30 15 13 0 23-5 30-15 6-7 8-18 8-33z m96 46l0-142-26 0 0 15c-10-12-20-17-29-17-9 0-15 3-17 10-2 5-3 12-3 22l0 112 26 0 0-105c0-6 1-9 1-10 0-4 2-6 6-6 5 0 10 4 16 12l0 109z"/>
|
||||
<glyph glyph-name="letter" unicode="L" d="M475 82l0 220c-6-7-12-13-19-19-51-39-92-72-122-97-10-8-18-14-24-19-6-4-14-9-24-14-11-4-21-7-30-7l0 0c-9 0-19 3-30 7-10 5-18 10-24 14-6 5-14 11-24 19-30 25-71 58-122 97-7 6-13 12-19 19l0-220c0-2 0-4 2-6 2-2 4-3 7-3l420 0c3 0 5 1 7 3 2 2 2 4 2 6z m0 301l0 7c0 0 0 1 0 3 0 3 0 4-1 4 0 0-1 1-1 2-1 2-2 3-3 3-1-1-2-1-4 0l-420 0c-3 0-5-1-7-2-2-2-2-4-2-7 0-32 14-59 42-81 36-29 75-59 114-91 1-1 5-3 10-8 6-5 10-8 13-11 4-2 8-5 13-9 5-3 10-6 14-8 5-1 9-2 13-2l0 0c4 0 8 1 13 2 4 2 9 5 14 8 5 4 9 7 13 9 3 3 7 6 13 11 5 5 9 7 10 8 39 32 78 62 114 91 11 8 20 19 29 33 9 14 13 26 13 38z m37 10l0-311c0-12-4-23-13-32-9-9-20-13-33-13l-420 0c-13 0-24 4-33 13-9 9-13 20-13 32l0 311c0 13 4 23 13 32 9 9 20 14 33 14l420 0c13 0 24-5 33-14 9-9 13-19 13-32z"/>
|
||||
<glyph glyph-name="no-notification" unicode="x" d="M261 27c0 3-2 5-5 5-11 0-21 4-29 12-8 8-12 18-12 29 0 3-2 5-5 5-3 0-4-2-4-5 0-14 5-26 14-35 10-10 22-15 36-15 3 0 5 1 5 4z m-154 136l251 217c-8 17-21 31-38 42-17 11-39 17-64 17-18 0-34-3-48-9-15-6-27-14-35-23-9-9-15-19-20-30-4-10-7-20-7-30 0-73-13-134-39-184z m387-53c0-10-4-19-11-26-7-7-16-11-26-11l-128 0c0-20-7-37-21-52-15-14-32-21-52-21-20 0-37 7-52 21-14 14-21 32-21 52l42 37 217 0c-32 35-54 79-65 131l32 28c11-68 40-121 85-159z m24 397l24-27c2-2 3-4 2-7 0-2-1-4-3-6l-534-464c-2-1-5-2-7-2-3 1-5 2-6 4l-24 27c-2 2-3 4-2 7 0 2 1 4 3 6l53 46c-4 6-6 12-6 19 10 8 18 16 26 25 8 9 16 20 25 34 8 14 15 29 21 45 6 16 10 36 14 59 4 23 6 48 6 74 0 29 11 56 33 81 22 25 52 40 88 45-2 4-2 8-2 12 0 7 2 14 8 19 5 5 11 8 19 8 8 0 14-3 19-8 6-5 8-12 8-19 0-4 0-8-2-12 24-3 45-11 63-23 18-12 32-27 42-45l119 104c2 1 5 2 7 2 3-1 5-2 6-4z"/>
|
||||
<glyph glyph-name="notification" unicode="n" d="M261 27c0 3-2 5-5 5-11 0-21 4-29 12-8 8-12 18-12 29 0 3-2 5-5 5-3 0-4-2-4-5 0-14 5-26 14-35 10-10 22-15 36-15 3 0 5 1 5 4z m233 83c0-10-4-19-11-26-7-7-16-11-26-11l-128 0c0-20-7-37-21-52-15-14-32-21-52-21-20 0-37 7-52 21-14 15-21 32-21 52l-128 0c-10 0-19 4-26 11-7 7-11 16-11 26 10 8 18 16 26 25 8 9 16 20 25 34 8 14 15 29 21 45 6 16 10 36 14 59 4 23 6 48 6 74 0 29 11 56 33 81 22 25 52 40 88 45-2 4-2 8-2 12 0 7 2 14 8 19 5 5 11 8 19 8 8 0 14-3 19-8 6-5 8-12 8-19 0-4 0-8-2-12 36-5 66-20 88-45 22-25 33-52 33-81 0-26 2-51 6-74 4-23 8-43 14-59 6-16 13-31 21-45 9-14 17-25 25-34 8-9 16-17 26-25z"/>
|
||||
<glyph glyph-name="circle" unicode="C" d="M475 256c0-40-9-77-29-110-20-34-46-60-80-80-33-20-70-29-110-29-40 0-77 9-110 29-34 20-60 46-80 80-20 33-29 70-29 110 0 40 9 77 29 110 20 34 46 60 80 80 33 20 70 29 110 29 40 0 77-9 110-29 34-20 60-46 80-80 20-33 29-70 29-110z"/>
|
||||
<glyph glyph-name="circle-o" unicode="M" d="M256 411c-28 0-54-7-78-20-24-14-43-33-57-57-13-24-20-50-20-78 0-28 7-54 20-78 14-24 33-43 57-57 24-13 50-20 78-20 28 0 54 7 78 20 24 14 43 33 57 57 13 24 20 50 20 78 0 28-7 54-20 78-14 24-33 43-57 57-24 13-50 20-78 20z m219-155c0-40-9-77-29-110-20-34-46-60-80-80-33-20-70-29-110-29-40 0-77 9-110 29-34 20-60 46-80 80-20 33-29 70-29 110 0 40 9 77 29 110 20 34 46 60 80 80 33 20 70 29 110 29 40 0 77-9 110-29 34-20 60-46 80-80 20-33 29-70 29-110z"/>
|
||||
</font></defs></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 22 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 45 KiB |
@@ -70,10 +70,6 @@ body.admin {
|
||||
.admin-content {
|
||||
margin-top: rem-calc(24);
|
||||
|
||||
.filters h2 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.proposal-new, .proposal-edit {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
@@ -38,116 +38,119 @@
|
||||
}
|
||||
|
||||
.icon-angle-down:before {
|
||||
content: "a";
|
||||
content: "\61";
|
||||
}
|
||||
.icon-angle-left:before {
|
||||
content: "b";
|
||||
content: "\62";
|
||||
}
|
||||
.icon-angle-right:before {
|
||||
content: "c";
|
||||
content: "\63";
|
||||
}
|
||||
.icon-angle-up:before {
|
||||
content: "d";
|
||||
content: "\64";
|
||||
}
|
||||
.icon-comments:before {
|
||||
content: "e";
|
||||
content: "\65";
|
||||
}
|
||||
.icon-twitter:before {
|
||||
content: "f";
|
||||
content: "\66";
|
||||
}
|
||||
.icon-calendar:before {
|
||||
content: "g";
|
||||
content: "\67";
|
||||
}
|
||||
.icon-debates:before {
|
||||
content: "i";
|
||||
content: "\69";
|
||||
}
|
||||
.icon-unlike:before {
|
||||
content: "j";
|
||||
content: "\6a";
|
||||
}
|
||||
.icon-like:before {
|
||||
content: "k";
|
||||
content: "\6b";
|
||||
}
|
||||
.icon-check:before {
|
||||
content: "l";
|
||||
content: "\6c";
|
||||
}
|
||||
.icon-edit:before {
|
||||
content: "m";
|
||||
}
|
||||
.icon-star:before {
|
||||
content: "n";
|
||||
content: "\6d";
|
||||
}
|
||||
.icon-user:before {
|
||||
content: "o";
|
||||
content: "\6f";
|
||||
}
|
||||
.icon-settings:before {
|
||||
content: "q";
|
||||
content: "\71";
|
||||
}
|
||||
.icon-stats:before {
|
||||
content: "r";
|
||||
content: "\72";
|
||||
}
|
||||
.icon-proposals:before {
|
||||
content: "h";
|
||||
content: "\68";
|
||||
}
|
||||
.icon-organizations:before {
|
||||
content: "s";
|
||||
content: "\73";
|
||||
}
|
||||
.icon-deleted:before {
|
||||
content: "t";
|
||||
content: "\74";
|
||||
}
|
||||
.icon-tag:before {
|
||||
content: "u";
|
||||
content: "\75";
|
||||
}
|
||||
.icon-eye:before {
|
||||
content: "p";
|
||||
content: "\70";
|
||||
}
|
||||
.icon-x:before {
|
||||
content: "v";
|
||||
content: "\76";
|
||||
}
|
||||
.icon-flag:before {
|
||||
content: "w";
|
||||
}
|
||||
.icon-notification:before {
|
||||
content: "x";
|
||||
content: "\77";
|
||||
}
|
||||
.icon-comment:before {
|
||||
content: "y";
|
||||
content: "\79";
|
||||
}
|
||||
.icon-reply:before {
|
||||
content: "z";
|
||||
content: "\7a";
|
||||
}
|
||||
.icon-facebook:before {
|
||||
content: "A";
|
||||
content: "\41";
|
||||
}
|
||||
.icon-google-plus:before {
|
||||
content: "B";
|
||||
}
|
||||
.icon-language:before {
|
||||
content: "C";
|
||||
content: "\42";
|
||||
}
|
||||
.icon-search:before {
|
||||
content: "E";
|
||||
content: "\45";
|
||||
}
|
||||
.icon-external:before {
|
||||
content: "F";
|
||||
content: "\46";
|
||||
}
|
||||
.icon-video:before {
|
||||
content: "D";
|
||||
content: "\44";
|
||||
}
|
||||
.icon-document:before {
|
||||
content: "G";
|
||||
content: "\47";
|
||||
}
|
||||
.icon-print:before {
|
||||
content: "H";
|
||||
content: "\48";
|
||||
}
|
||||
.icon-blog:before {
|
||||
content: "J";
|
||||
content: "\4a";
|
||||
}
|
||||
.icon-box:before {
|
||||
content: "I";
|
||||
content: "\49";
|
||||
}
|
||||
.icon-youtube:before {
|
||||
content: "K";
|
||||
content: "\4b";
|
||||
}
|
||||
.icon-letter:before {
|
||||
content: "L";
|
||||
}
|
||||
content: "\4c";
|
||||
}
|
||||
.icon-no-notification:before {
|
||||
content: "\78";
|
||||
}
|
||||
.icon-notification:before {
|
||||
content: "\6e";
|
||||
}
|
||||
.icon-circle:before {
|
||||
content: "\43";
|
||||
}
|
||||
.icon-circle-o:before {
|
||||
content: "\4d";
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// 06. Forms
|
||||
// 07. Alerts
|
||||
// 08. User account
|
||||
// 09. Filters & search
|
||||
// 09. Search
|
||||
// 10. Official levels
|
||||
// 11. Pagination
|
||||
// 12. Tables
|
||||
@@ -220,6 +220,16 @@ a {
|
||||
}
|
||||
}
|
||||
|
||||
.sub-nav {
|
||||
border-bottom: 1px solid $border;
|
||||
|
||||
dd.active {
|
||||
border-bottom: 2px solid $brand;
|
||||
color: $brand;
|
||||
padding-bottom: $line-height/4;
|
||||
}
|
||||
}
|
||||
|
||||
// 02. Header
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
@@ -396,7 +406,6 @@ header {
|
||||
&:hover {
|
||||
background: none;
|
||||
color: white;
|
||||
text-decoration: underline;
|
||||
transition: text-decoration 275ms;
|
||||
}
|
||||
|
||||
@@ -420,6 +429,7 @@ header {
|
||||
|
||||
&:hover, &:focus {
|
||||
background-color: #007095 !important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,11 +639,7 @@ footer {
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
|
||||
@media (min-width: $small-breakpoint) {
|
||||
padding-top: $line-height*2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
h1:not(.logo) {
|
||||
@include logo;
|
||||
|
||||
a {
|
||||
@@ -651,25 +657,18 @@ footer {
|
||||
}
|
||||
|
||||
.auth {
|
||||
min-height: $line-height*20;
|
||||
|
||||
.back, .icon-angle-left {
|
||||
@include back;
|
||||
}
|
||||
|
||||
p, a {
|
||||
font-family: $font-sans;
|
||||
p, a, .checkbox {
|
||||
font-size: $small-font-size;
|
||||
}
|
||||
|
||||
.panel {
|
||||
background: white;
|
||||
border: 0;
|
||||
|
||||
h1 {
|
||||
font-size: rem-calc(30);
|
||||
font-weight: bolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -947,60 +946,80 @@ img.avatar, img.admin-avatar, img.moderator-avatar, img.initialjs-avatar {
|
||||
}
|
||||
}
|
||||
|
||||
// 09. Filters & search
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
.notifications {
|
||||
position: relative;
|
||||
|
||||
.filters, .search-results {
|
||||
|
||||
h2 {
|
||||
display: inline-block;
|
||||
font-size: rem-calc(24);
|
||||
margin: $line-height/2 0;
|
||||
|
||||
@media (min-width: $small-breakpoint) {
|
||||
margin: $line-height 0;
|
||||
}
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
select {
|
||||
background-color: #DEE0E2;
|
||||
height: auto;
|
||||
margin-bottom: $line-height;
|
||||
min-width: $line-height*7.5;
|
||||
outline: 0;
|
||||
padding: $line-height/2;
|
||||
width: auto;
|
||||
|
||||
@media (min-width: $small-breakpoint) {
|
||||
margin: 0 0 $line-height $line-height/2;
|
||||
}
|
||||
|
||||
optgroup {
|
||||
font-size: $small-font-size;
|
||||
}
|
||||
|
||||
option {
|
||||
|
||||
&:after {
|
||||
content: "a";
|
||||
font-family: "icons";
|
||||
}
|
||||
}
|
||||
[class^="icon-"] {
|
||||
font-size: $h4-font-size;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.debates-order {
|
||||
text-align: left;
|
||||
|
||||
@media (min-width: $small-breakpoint) {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
select {
|
||||
margin-left: 0;
|
||||
}
|
||||
.icon-circle {
|
||||
color: #ecf00b;
|
||||
font-size: $tiny-font-size;
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
top: -6px;
|
||||
}
|
||||
}
|
||||
|
||||
.notifications-list:before {
|
||||
background: $border;
|
||||
content: '';
|
||||
height: 100%;
|
||||
left: 28px;
|
||||
position: absolute;
|
||||
top: 84px;
|
||||
width: 2px;
|
||||
}
|
||||
|
||||
.notification {
|
||||
display: block;
|
||||
padding: $line-height/2 0 $line-height/2 $line-height*1.5;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
p:not(.time) {
|
||||
color: $link;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: "\43";
|
||||
}
|
||||
}
|
||||
|
||||
&:before {
|
||||
background: white;
|
||||
color: $brand;
|
||||
content: "\4d";
|
||||
font-family: "icons" !important;
|
||||
left: 6px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
p {
|
||||
color: $text;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: $small-font-size;
|
||||
color: $text-medium;
|
||||
}
|
||||
}
|
||||
|
||||
// 09. Search
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
.search-form {
|
||||
|
||||
h3 {
|
||||
@@ -1574,7 +1593,6 @@ table {
|
||||
font-family: $font-sans;
|
||||
font-size: $small-font-size;
|
||||
line-height: $line-height;
|
||||
margin: rem-calc(10) $line-height/2 $line-height/4 0;
|
||||
|
||||
a {
|
||||
color: $text-light;
|
||||
@@ -1595,15 +1613,12 @@ table {
|
||||
.comment-body {
|
||||
margin-left: rem-calc(42);
|
||||
|
||||
p {
|
||||
font-size: $small-font-size;
|
||||
}
|
||||
|
||||
.reply {
|
||||
background: white;
|
||||
border: 1px solid $border;
|
||||
font-family: $font-sans;
|
||||
font-size: rem-calc(12);
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
font-size: $small-font-size;
|
||||
margin: rem-calc(6) 0;
|
||||
padding: rem-calc(6);
|
||||
|
||||
@@ -1735,17 +1750,6 @@ table {
|
||||
|
||||
.activity {
|
||||
margin-bottom: $line-height*2;
|
||||
margin-top: $line-height;
|
||||
|
||||
.sub-nav {
|
||||
border-bottom: 1px solid $border;
|
||||
|
||||
dd.active {
|
||||
border-bottom: 2px solid $brand;
|
||||
color: $brand;
|
||||
padding-bottom: $line-height/4;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
border: 0;
|
||||
|
||||
@@ -789,8 +789,12 @@
|
||||
// 05. Featured
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
.featured-debates-container {
|
||||
background: $votes-bg;
|
||||
.featured-debates, .featured-proposals {
|
||||
padding: $line-height/2 0;
|
||||
|
||||
@media (min-width: $small-breakpoint) {
|
||||
margin-top: $line-height !important;
|
||||
}
|
||||
|
||||
@media (min-width: $medium-breakpoint) {
|
||||
margin-left: 0 !important;
|
||||
@@ -798,134 +802,40 @@
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.debates-list {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.featured-proposals-container {
|
||||
background: #FED900;
|
||||
|
||||
@media (min-width: $medium-breakpoint) {
|
||||
margin-left: 0 !important;
|
||||
margin-right: rem-calc(-15) !important;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: $text;
|
||||
|
||||
@media (min-width: $medium-breakpoint) {
|
||||
margin-bottom: rem-calc(27);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.featured-debates-container, .featured-proposals-container {
|
||||
margin: $line-height 0 !important;
|
||||
|
||||
h2 {
|
||||
font-size: rem-calc(24);
|
||||
margin: rem-calc(12) 0 0;
|
||||
position: relative;
|
||||
font-size: $small-font-size;
|
||||
line-height: $line-height;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.icon-proposals {
|
||||
font-size: rem-calc(20);
|
||||
position: absolute;
|
||||
right: -26px;
|
||||
top: -5px;
|
||||
h3 {
|
||||
margin-bottom: 0;
|
||||
|
||||
a {
|
||||
color: $text;
|
||||
font-size: $h3-font-size;
|
||||
}
|
||||
}
|
||||
|
||||
.debates-list {
|
||||
|
||||
@media (min-width: $medium-breakpoint) {
|
||||
border-left: 1px solid $votes-border;
|
||||
}
|
||||
|
||||
&:after {
|
||||
|
||||
@media (min-width: $medium-breakpoint) {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
a, .info {
|
||||
color: lighten($text, 15%);
|
||||
font-size: $small-font-size;
|
||||
}
|
||||
|
||||
.proposals-list {
|
||||
|
||||
@media (min-width: $medium-breakpoint) {
|
||||
border-left: 1px solid #D2B400;
|
||||
}
|
||||
|
||||
&:after {
|
||||
border-color: #C9AF00 transparent transparent transparent;
|
||||
|
||||
@media (min-width: $medium-breakpoint) {
|
||||
content: " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.debates-list, .proposals-list {
|
||||
margin: rem-calc(6) 0;
|
||||
|
||||
&:after {
|
||||
content: none;
|
||||
position: absolute;
|
||||
display: block;
|
||||
border-style: solid;
|
||||
bottom: rem-calc(-20);
|
||||
border-left-width: 0;
|
||||
border-right-color: transparent;
|
||||
right: rem-calc(1);
|
||||
border-width: rem-calc(14) rem-calc(14) 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.debate-featured, .proposal-featured {
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
padding-left: 0;
|
||||
.featured-debates {
|
||||
background: $highlight;
|
||||
}
|
||||
|
||||
.panel {
|
||||
background: none;
|
||||
border: 0;
|
||||
margin-bottom: 0;
|
||||
padding: 0 rem-calc(12);
|
||||
|
||||
h3 {
|
||||
font-weight: bold;
|
||||
margin: rem-calc(8) 0 0 0;
|
||||
min-height: auto;
|
||||
|
||||
a {
|
||||
clear: both;
|
||||
display: block;
|
||||
font-size: rem-calc(14);
|
||||
line-height: $line-height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.progress {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.content {
|
||||
overflow: hidden;
|
||||
}
|
||||
.featured-proposals {
|
||||
background: $featured;
|
||||
|
||||
.supports {
|
||||
@include supports;
|
||||
background: none;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
padding-left: rem-calc(13);
|
||||
margin-right: rem-calc(-26);
|
||||
padding-bottom: 0;
|
||||
padding-top: 0;
|
||||
|
||||
&:after {
|
||||
content: none;
|
||||
@@ -935,8 +845,12 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.button-support {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.not-logged, .organizations-votes {
|
||||
background: #FED900;
|
||||
background: $featured;
|
||||
color: $warning-color;
|
||||
font-size: $small-font-size;
|
||||
line-height: rem-calc(24);
|
||||
@@ -949,14 +863,12 @@
|
||||
}
|
||||
|
||||
.anonymous-votes {
|
||||
background: #FED900;
|
||||
padding: 0;
|
||||
padding-top: rem-calc(6);
|
||||
background: $featured;
|
||||
|
||||
p {
|
||||
font-size: rem-calc(12);
|
||||
line-height: rem-calc(20);
|
||||
margin: 0;
|
||||
color: $text;
|
||||
font-size: $small-font-size;
|
||||
line-height: $line-height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -967,10 +879,6 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.button-support {
|
||||
margin-top: rem-calc(4);
|
||||
}
|
||||
|
||||
.supported {
|
||||
margin-top: 0;
|
||||
}
|
||||
@@ -981,53 +889,12 @@
|
||||
.social-share-button-facebook,
|
||||
.social-share-button-google_plus {
|
||||
height: rem-calc(33);
|
||||
}
|
||||
|
||||
.social-share-button-twitter:before,
|
||||
.social-share-button-facebook:before,
|
||||
.social-share-button-google_plus:before {
|
||||
font-size: rem-calc(18);
|
||||
line-height: rem-calc(33);
|
||||
&:before {
|
||||
font-size: rem-calc(18);
|
||||
line-height: rem-calc(33);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.debate-featured {
|
||||
background: $votes-bg;
|
||||
margin-bottom: rem-calc(12) !important;
|
||||
|
||||
.panel h3 a {
|
||||
color: #0D3F54;
|
||||
font-size: $h3-font-size;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.info, .info a {
|
||||
color: white !important;
|
||||
font-family: $font-sans;
|
||||
font-size: $small-font-size;
|
||||
}
|
||||
|
||||
.content {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.proposal-featured {
|
||||
background: #FED900;
|
||||
|
||||
.panel h3 a {
|
||||
color: $text;
|
||||
font-size: $base-font-size;
|
||||
}
|
||||
|
||||
.info {
|
||||
color: #806C00 !important;
|
||||
font-size: $small-font-size;
|
||||
}
|
||||
|
||||
.content {
|
||||
height: rem-calc(60);
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ $h6-font-size: rem-calc(13);
|
||||
$h6-line-height: rem-calc(17);
|
||||
|
||||
$small-font-size: rem-calc(14);
|
||||
$tiny-font-size: rem-calc(10);
|
||||
$line-height: rem-calc(24);
|
||||
|
||||
// 02. Colors
|
||||
@@ -73,6 +74,7 @@ $proposals: #FFA42D;
|
||||
$proposals-border: #CC8425;
|
||||
|
||||
$highlight: #E7F2FC;
|
||||
$featured: #FED900;
|
||||
|
||||
$footer-bg: #DEE0E2;
|
||||
$footer-color: #171819;
|
||||
|
||||
23
app/controllers/admin/spending_proposals_controller.rb
Normal file
23
app/controllers/admin/spending_proposals_controller.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
class Admin::SpendingProposalsController < Admin::BaseController
|
||||
has_filters %w{unresolved accepted rejected}, only: :index
|
||||
|
||||
load_and_authorize_resource
|
||||
|
||||
def index
|
||||
@spending_proposals = @spending_proposals.includes([:geozone]).send(@current_filter).order(created_at: :desc).page(params[:page])
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def accept
|
||||
@spending_proposal.accept
|
||||
redirect_to request.query_parameters.merge(action: :index)
|
||||
end
|
||||
|
||||
def reject
|
||||
@spending_proposal.reject
|
||||
redirect_to request.query_parameters.merge(action: :index)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -108,4 +108,5 @@ class ApplicationController < ActionController::Base
|
||||
store_location_for(:user, request.path)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class CommentsController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :authenticate_user!, only: :create
|
||||
before_action :load_commentable, only: :create
|
||||
before_action :build_comment, only: :create
|
||||
|
||||
@@ -9,11 +9,17 @@ class CommentsController < ApplicationController
|
||||
def create
|
||||
if @comment.save
|
||||
CommentNotifier.new(comment: @comment).process
|
||||
add_notification @comment
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@comment = Comment.find(params[:id])
|
||||
set_comment_flags(@comment.subtree)
|
||||
end
|
||||
|
||||
def vote
|
||||
@comment.vote_by(voter: current_user, vote: params[:value])
|
||||
respond_with @comment
|
||||
@@ -62,4 +68,13 @@ class CommentsController < ApplicationController
|
||||
["1", true].include?(comment_params[:as_moderator]) && can?(:comment_as_moderator, @commentable)
|
||||
end
|
||||
|
||||
def add_notification(comment)
|
||||
if comment.reply?
|
||||
notifiable = comment.parent
|
||||
else
|
||||
notifiable = comment.commentable
|
||||
end
|
||||
Notification.add(notifiable.author_id, notifiable) unless comment.author_id == notifiable.author_id
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -30,4 +30,4 @@ class Moderation::UsersController < Moderation::BaseController
|
||||
Activity.log(current_user, :block, @user)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
26
app/controllers/notifications_controller.rb
Normal file
26
app/controllers/notifications_controller.rb
Normal file
@@ -0,0 +1,26 @@
|
||||
class NotificationsController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
after_action :mark_as_read, only: :show
|
||||
skip_authorization_check
|
||||
|
||||
def index
|
||||
@notifications = current_user.notifications.unread.recent.for_render
|
||||
end
|
||||
|
||||
def show
|
||||
@notification = current_user.notifications.find(params[:id])
|
||||
redirect_to url_for(@notification.notifiable)
|
||||
end
|
||||
|
||||
def mark_all_as_read
|
||||
current_user.notifications.each { |notification| notification.mark_as_read }
|
||||
redirect_to notifications_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def mark_as_read
|
||||
@notification.mark_as_read
|
||||
end
|
||||
|
||||
end
|
||||
32
app/controllers/spending_proposals_controller.rb
Normal file
32
app/controllers/spending_proposals_controller.rb
Normal file
@@ -0,0 +1,32 @@
|
||||
class SpendingProposalsController < ApplicationController
|
||||
before_action :authenticate_user!, except: [:index]
|
||||
|
||||
load_and_authorize_resource
|
||||
|
||||
def index
|
||||
end
|
||||
|
||||
def new
|
||||
@spending_proposal = SpendingProposal.new
|
||||
@featured_tags = ActsAsTaggableOn::Tag.where(featured: true)
|
||||
end
|
||||
|
||||
def create
|
||||
@spending_proposal = SpendingProposal.new(spending_proposal_params)
|
||||
@spending_proposal.author = current_user
|
||||
|
||||
if @spending_proposal.save_with_captcha
|
||||
redirect_to spending_proposals_path, notice: t('flash.actions.create.notice', resource_name: t("activerecord.models.spending_proposal", count: 1))
|
||||
else
|
||||
@featured_tags = ActsAsTaggableOn::Tag.where(featured: true)
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def spending_proposal_params
|
||||
params.require(:spending_proposal).permit(:title, :description, :external_url, :geozone_id, :terms_of_service, :captcha, :captcha_key)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -13,8 +13,11 @@ module CommentsHelper
|
||||
end
|
||||
|
||||
def child_comments_of(parent)
|
||||
return [] unless @comment_tree
|
||||
@comment_tree.children_of(parent)
|
||||
if @comment_tree.present?
|
||||
@comment_tree.ordered_children_of(parent)
|
||||
else
|
||||
parent.children
|
||||
end
|
||||
end
|
||||
|
||||
def user_level_class(comment)
|
||||
|
||||
11
app/helpers/geozones_helper.rb
Normal file
11
app/helpers/geozones_helper.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
module GeozonesHelper
|
||||
|
||||
def geozone_name(geozonable)
|
||||
geozonable.geozone ? geozonable.geozone.name : t("geozones.none")
|
||||
end
|
||||
|
||||
def geozone_select_options
|
||||
Geozone.all.order(name: :asc).collect { |g| [ g.name, g.id ] }
|
||||
end
|
||||
|
||||
end
|
||||
6
app/helpers/notifications_helper.rb
Normal file
6
app/helpers/notifications_helper.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
module NotificationsHelper
|
||||
|
||||
def notification_action(notification)
|
||||
notification.notifiable_type == "Comment" ? "replies_to" : "comments_on"
|
||||
end
|
||||
end
|
||||
@@ -34,6 +34,8 @@ module Abilities
|
||||
can [:search, :create, :index, :destroy], ::Moderator
|
||||
|
||||
can :manage, Annotation
|
||||
|
||||
can :manage, SpendingProposal
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,6 +17,8 @@ module Abilities
|
||||
proposal.editable_by?(user)
|
||||
end
|
||||
|
||||
can :read, SpendingProposal
|
||||
|
||||
can :create, Comment
|
||||
can :create, Debate
|
||||
can :create, Proposal
|
||||
@@ -38,6 +40,7 @@ module Abilities
|
||||
if user.level_two_or_three_verified?
|
||||
can :vote, Proposal
|
||||
can :vote_featured, Proposal
|
||||
can :create, SpendingProposal
|
||||
end
|
||||
|
||||
can :create, Annotation
|
||||
|
||||
@@ -5,6 +5,8 @@ module Abilities
|
||||
def initialize(user)
|
||||
can :read, Debate
|
||||
can :read, Proposal
|
||||
can :read, Comment
|
||||
can :read, SpendingProposal
|
||||
can :read, Legislation
|
||||
can :read, User
|
||||
can [:search, :read], Annotation
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class Activity < ActiveRecord::Base
|
||||
|
||||
belongs_to :actionable, -> { with_hidden }, polymorphic: true
|
||||
belongs_to :user, -> { with_hidden }
|
||||
|
||||
@@ -24,5 +23,4 @@ class Activity < ActiveRecord::Base
|
||||
def self.by(user)
|
||||
where(user: user)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -13,7 +13,7 @@ module Sanitizable
|
||||
end
|
||||
|
||||
def sanitize_tag_list
|
||||
self.tag_list = TagSanitizer.new.sanitize_tag_list(self.tag_list)
|
||||
self.tag_list = TagSanitizer.new.sanitize_tag_list(self.tag_list) if self.class.taggable?
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
3
app/models/geozone.rb
Normal file
3
app/models/geozone.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
class Geozone < ActiveRecord::Base
|
||||
validates :name, presence: true
|
||||
end
|
||||
24
app/models/notification.rb
Normal file
24
app/models/notification.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
class Notification < ActiveRecord::Base
|
||||
belongs_to :user, counter_cache: true
|
||||
belongs_to :notifiable, polymorphic: true
|
||||
|
||||
scope :unread, -> { all }
|
||||
scope :recent, -> { order(id: :desc) }
|
||||
scope :for_render, -> { includes(:notifiable) }
|
||||
|
||||
def timestamp
|
||||
notifiable.created_at
|
||||
end
|
||||
|
||||
def mark_as_read
|
||||
self.destroy
|
||||
end
|
||||
|
||||
def self.add(user_id, notifiable)
|
||||
if notification = Notification.find_by(user_id: user_id, notifiable: notifiable)
|
||||
Notification.increment_counter(:counter, notification.id)
|
||||
else
|
||||
Notification.create!(user_id: user_id, notifiable: notifiable)
|
||||
end
|
||||
end
|
||||
end
|
||||
44
app/models/spending_proposal.rb
Normal file
44
app/models/spending_proposal.rb
Normal file
@@ -0,0 +1,44 @@
|
||||
class SpendingProposal < ActiveRecord::Base
|
||||
include Measurable
|
||||
include Sanitizable
|
||||
|
||||
apply_simple_captcha
|
||||
|
||||
RESOLUTIONS = ["accepted", "rejected"]
|
||||
|
||||
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
|
||||
belongs_to :geozone
|
||||
|
||||
validates :title, presence: true
|
||||
validates :author, presence: true
|
||||
validates :description, presence: true
|
||||
|
||||
validates :title, length: { in: 4..SpendingProposal.title_max_length }
|
||||
validates :description, length: { maximum: SpendingProposal.description_max_length }
|
||||
validates :resolution, inclusion: { in: RESOLUTIONS, allow_nil: true }
|
||||
validates :terms_of_service, acceptance: { allow_nil: false }, on: :create
|
||||
|
||||
scope :accepted, -> { where(resolution: "accepted") }
|
||||
scope :rejected, -> { where(resolution: "rejected") }
|
||||
scope :unresolved, -> { where(resolution: nil) }
|
||||
|
||||
def accept
|
||||
update_attribute(:resolution, "accepted")
|
||||
end
|
||||
|
||||
def reject
|
||||
update_attribute(:resolution, "rejected")
|
||||
end
|
||||
|
||||
def accepted?
|
||||
resolution == "accepted"
|
||||
end
|
||||
|
||||
def rejected?
|
||||
resolution == "rejected"
|
||||
end
|
||||
|
||||
def unresolved?
|
||||
resolution.blank?
|
||||
end
|
||||
end
|
||||
@@ -22,6 +22,7 @@ class User < ActiveRecord::Base
|
||||
has_many :proposals, -> { with_hidden }, foreign_key: :author_id
|
||||
has_many :comments, -> { with_hidden }
|
||||
has_many :failed_census_calls
|
||||
has_many :notifications
|
||||
|
||||
validates :username, presence: true, if: :username_required?
|
||||
validates :username, uniqueness: true, if: :username_required?
|
||||
@@ -199,7 +200,7 @@ class User < ActiveRecord::Base
|
||||
def email_required?
|
||||
!erased?
|
||||
end
|
||||
|
||||
|
||||
def has_official_email?
|
||||
domain = Setting.value_for 'email_domain_for_officials'
|
||||
!email.blank? && ( (email.end_with? "@#{domain}") || (email.end_with? ".#{domain}") )
|
||||
|
||||
@@ -32,6 +32,13 @@
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "spending_proposals" %>>
|
||||
<%= link_to admin_spending_proposals_path do %>
|
||||
<i class="icon-proposals"></i>
|
||||
<%= t("admin.menu.spending_proposals") %>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "users" %>>
|
||||
<%= link_to admin_users_path do %>
|
||||
<i class="icon-eye"></i>
|
||||
|
||||
36
app/views/admin/spending_proposals/index.html.erb
Normal file
36
app/views/admin/spending_proposals/index.html.erb
Normal file
@@ -0,0 +1,36 @@
|
||||
<h2><%= t("admin.spending_proposals.index.title") %></h2>
|
||||
|
||||
<%= render 'shared/filter_subnav', i18n_namespace: "admin.spending_proposals.index" %>
|
||||
|
||||
<h3><%= page_entries_info @spending_proposals %></h3>
|
||||
|
||||
<table>
|
||||
<% @spending_proposals.each do |spending_proposal| %>
|
||||
<tr id="<%= dom_id(spending_proposal) %>">
|
||||
<td>
|
||||
<strong><%= link_to spending_proposal.title, admin_spending_proposal_path(spending_proposal) %></strong>
|
||||
</td>
|
||||
<td>
|
||||
<%= geozone_name(spending_proposal) %>
|
||||
</td>
|
||||
<td>
|
||||
<% unless spending_proposal.accepted? %>
|
||||
<%= link_to t("admin.spending_proposals.actions.accept"),
|
||||
accept_admin_spending_proposal_path(spending_proposal, request.query_parameters),
|
||||
method: :put,
|
||||
data: { confirm: t("admin.actions.confirm") },
|
||||
class: "button radius tiny success no-margin" %>
|
||||
<% end %>
|
||||
<% unless spending_proposal.rejected? %>
|
||||
<%= link_to t("admin.spending_proposals.actions.reject"),
|
||||
reject_admin_spending_proposal_path(spending_proposal, request.query_parameters),
|
||||
method: :put,
|
||||
data: { confirm: t("admin.actions.confirm") },
|
||||
class: "button radius tiny warning right" %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
|
||||
<%= paginate @spending_proposals %>
|
||||
28
app/views/admin/spending_proposals/show.html.erb
Normal file
28
app/views/admin/spending_proposals/show.html.erb
Normal file
@@ -0,0 +1,28 @@
|
||||
<h2><%= @spending_proposal.title %></h2>
|
||||
|
||||
<%= safe_html_with_links @spending_proposal.description.html_safe %>
|
||||
|
||||
<% if @spending_proposal.external_url.present? %>
|
||||
<p><%= text_with_links @spending_proposal.external_url %></p>
|
||||
<% end %>
|
||||
|
||||
<p><%= t("admin.spending_proposals.show.by") %>: <%= link_to @spending_proposal.author.name, admin_user_path(@spending_proposal.author) %></p>
|
||||
<p><%= t("admin.spending_proposals.show.geozone") %>: <%= geozone_name(@spending_proposal) %></p>
|
||||
<p><%= l @spending_proposal.created_at, format: :datetime %></p>
|
||||
|
||||
<p>
|
||||
<% unless @spending_proposal.accepted? %>
|
||||
<%= link_to t("admin.spending_proposals.actions.accept"),
|
||||
accept_admin_spending_proposal_path(@spending_proposal),
|
||||
method: :put,
|
||||
data: { confirm: t("admin.actions.confirm") },
|
||||
class: "button radius tiny success no-margin" %>
|
||||
<% end %>
|
||||
<% unless @spending_proposal.rejected? %>
|
||||
<%= link_to t("admin.spending_proposals.actions.reject"),
|
||||
reject_admin_spending_proposal_path(@spending_proposal),
|
||||
method: :put,
|
||||
data: { confirm: t("admin.actions.confirm") },
|
||||
class: "button radius tiny warning" %>
|
||||
<% end %>
|
||||
</p>
|
||||
@@ -1,9 +1,9 @@
|
||||
<% cache [locale_and_user_status(comment), comment, commentable_cache_key(@commentable), comment.author, (@comment_flags[comment.id] if @comment_flags)] do %>
|
||||
<% cache [locale_and_user_status(comment), comment, commentable_cache_key(comment.commentable), comment.author, (@comment_flags[comment.id] if @comment_flags)] do %>
|
||||
<div class="row">
|
||||
<div id="<%= dom_id(comment) %>" class="comment small-12 column">
|
||||
|
||||
<% if comment.hidden? || comment.user.hidden? %>
|
||||
<% if child_comments_of(comment).size > 0 %>
|
||||
<% if comment.children.size > 0 %>
|
||||
<div class="is-deleted">
|
||||
<p><%= t("comments.comment.deleted") %></p>
|
||||
</div>
|
||||
@@ -49,7 +49,7 @@
|
||||
<%= t("shared.collective") %>
|
||||
</span>
|
||||
<% end %>
|
||||
<% if comment.user_id == @commentable.author_id %>
|
||||
<% if comment.user_id == comment.commentable.author_id %>
|
||||
•
|
||||
<span class="label round is-author">
|
||||
<%= t("comments.comment.author") %>
|
||||
@@ -63,16 +63,16 @@
|
||||
|
||||
<div class="comment-user
|
||||
<%= user_level_class comment %>
|
||||
<%= comment_author_class comment, @commentable.author_id %>">
|
||||
<%= comment_author_class comment, comment.commentable.author_id %>">
|
||||
<%= simple_format text_with_links comment.body %>
|
||||
</div>
|
||||
|
||||
<span id="<%= dom_id(comment) %>_votes" class="comment-votes right">
|
||||
<%= render 'comments/votes', comment: comment %>
|
||||
</span>
|
||||
<div id="<%= dom_id(comment) %>_reply" class="reply">
|
||||
<span id="<%= dom_id(comment) %>_votes" class="comment-votes right">
|
||||
<%= render 'comments/votes', comment: comment %>
|
||||
</span>
|
||||
|
||||
<div class="reply">
|
||||
<%= t("comments.comment.responses", count: child_comments_of(comment).size) %>
|
||||
<%= t("comments.comment.responses", count: comment.children.size) %>
|
||||
|
||||
<% if user_signed_in? %>
|
||||
<span class="divider"> | </span>
|
||||
@@ -81,11 +81,12 @@
|
||||
|
||||
<%= render 'comments/actions', comment: comment %>
|
||||
|
||||
<%= render 'comments/form', {commentable: @commentable, parent_id: comment.id, toggeable: true} %>
|
||||
<%= render 'comments/form', {commentable: comment.commentable, parent_id: comment.id, toggeable: true} %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="comment-children">
|
||||
<% child_comments_of(comment).each do |child| %>
|
||||
<%= render 'comments/comment', comment: child %>
|
||||
|
||||
16
app/views/comments/show.html.erb
Normal file
16
app/views/comments/show.html.erb
Normal file
@@ -0,0 +1,16 @@
|
||||
<div class="row">
|
||||
<div class="small-12 column margin-top">
|
||||
<%= link_to @comment.commentable, class: "left back" do %>
|
||||
<i class="icon-angle-left left"></i>
|
||||
<%= t("comments.show.return_to_commentable") + @comment.commentable.title %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="comments">
|
||||
<div class="row">
|
||||
<div id="comments" class="small-12 column">
|
||||
<%= render @comment %>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1,41 +1,17 @@
|
||||
<div id="featured-debates" class="row featured-debates-container">
|
||||
<div class="small-12 medium-3 column">
|
||||
<h2>
|
||||
<%= t("debates.index.featured_debates_html") %>
|
||||
</h2>
|
||||
<span class="show-for-medium-up">
|
||||
<%= image_tag("featured_debates.jpg", size: "210x135") %>
|
||||
</span>
|
||||
<div id="featured-debates" class="row featured-debates">
|
||||
|
||||
<div class="small-12 column">
|
||||
<h2><%= t("debates.index.featured_debates") %></h2>
|
||||
</div>
|
||||
<div class="small-12 medium-9 column debates-list">
|
||||
|
||||
<div class="debate-featured small-12 column">
|
||||
<div class="panel">
|
||||
<div class="content small-12 left">
|
||||
<h3>
|
||||
<%= link_to "#Túpreguntas: Manuela Carmena, Alcaldesa de Madrid.", "https://decide.madrid.es/debates/4320" %></h3>
|
||||
<div class="info">
|
||||
<span class="author">
|
||||
<%= link_to "Manuela Carmena ", "https://decide.madrid.es/users/21452"%>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="debate-featured small-12 column">
|
||||
<div class="panel">
|
||||
<div class="content small-12 left">
|
||||
<h3>
|
||||
<%= link_to "¿Y si cualquiera pudiera entrevistar a Manuela Carmena o a los otros concejales?", "https://decide.madrid.es/debates/4299" %></h3>
|
||||
<div class="info">
|
||||
<span class="author">
|
||||
<%= link_to "ParticipaciónYTransparenciaAytoMadrid", "https://decide.madrid.es/users/52055"%>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-6 column">
|
||||
<h3><%= link_to "#Túpreguntas: Manuela Carmena, Alcaldesa de Madrid.", "https://decide.madrid.es/debates/4320" %></h3>
|
||||
<%= link_to "Manuela Carmena ", "https://decide.madrid.es/users/21452"%>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-6 column">
|
||||
<h3><%= link_to "¿Y si pudieras entrevistar a Manuela Carmena o a los otros concejales?", "https://decide.madrid.es/debates/4299" %></h3>
|
||||
<%= link_to "ParticipaciónYTransparenciaAytoMadrid", "https://decide.madrid.es/users/52055"%>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -9,34 +9,32 @@
|
||||
<div class="wrap row">
|
||||
<div id="debates" class="debates-list small-12 medium-9 column">
|
||||
|
||||
<div class="filters">
|
||||
<div class="small-12 medium-7 left">
|
||||
<% if @search_terms %>
|
||||
<h2 class="margin-top">
|
||||
<%= page_entries_info @debates %>
|
||||
<%= t("debates.index.search_results", count: @debates.size, search_term: @search_terms) %>
|
||||
</h2>
|
||||
<% elsif @tag_filter %>
|
||||
<h2 class="margin-top">
|
||||
<%= page_entries_info @debates %>
|
||||
<%= t("debates.index.filter_topic", count: @debates.size, topic: @tag_filter) %>
|
||||
</h2>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% unless @tag_filter || @search_terms %>
|
||||
<%= render "featured_debates_static" %>
|
||||
<div class="small-12 medium-7 left">
|
||||
<% if @search_terms %>
|
||||
<h2 class="margin-top">
|
||||
<%= page_entries_info @debates %>
|
||||
<%= t("debates.index.search_results", count: @debates.size, search_term: @search_terms) %>
|
||||
</h2>
|
||||
<% elsif @tag_filter %>
|
||||
<h2 class="margin-top">
|
||||
<%= page_entries_info @debates %>
|
||||
<%= t("debates.index.filter_topic", count: @debates.size, topic: @tag_filter) %>
|
||||
</h2>
|
||||
<% end %>
|
||||
|
||||
<%= render 'shared/order_links', i18n_namespace: "debates.index" %>
|
||||
|
||||
<div class="show-for-small-only">
|
||||
<%= link_to t("debates.index.start_debate"), new_debate_path, class: 'button radius expand' %>
|
||||
</div>
|
||||
|
||||
<%= render @debates %>
|
||||
<%= paginate @debates %>
|
||||
</div>
|
||||
|
||||
<% unless @tag_filter || @search_terms %>
|
||||
<%= render "featured_debates_static" %>
|
||||
<% end %>
|
||||
|
||||
<%= render 'shared/order_links', i18n_namespace: "debates.index" %>
|
||||
|
||||
<div class="show-for-small-only">
|
||||
<%= link_to t("debates.index.start_debate"), new_debate_path, class: 'button radius expand' %>
|
||||
</div>
|
||||
|
||||
<%= render @debates %>
|
||||
<%= paginate @debates %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-3 column">
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
<ul class="right">
|
||||
<% if user_signed_in? %>
|
||||
<li>
|
||||
<%= link_to notifications_path, class: "notifications" do %>
|
||||
<% if current_user.notifications_count > 0 %>
|
||||
<i class="icon-circle"></i>
|
||||
<i class="icon-notification" title="<%= t('layouts.header.new_notifications', count: current_user.notifications_count).html_safe %>">
|
||||
</i>
|
||||
<% else %>
|
||||
<i class="icon-no-notification" title="<%= t('layouts.header.no_notifications') %>"></i>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to(t("layouts.header.my_activity_link"), user_path(current_user)) %>
|
||||
</li>
|
||||
|
||||
@@ -33,14 +33,16 @@
|
||||
</section>
|
||||
|
||||
<section class="subnavigation row">
|
||||
|
||||
<div class="small-12 medium-9 column">
|
||||
<%= link_to t("layouts.header.debates"), debates_path, class: ("active" if current_page?(controller: "/debates")) %>
|
||||
<%= link_to t("layouts.header.proposals"), proposals_path, class: ("active" if current_page?(controller: "/proposals")) %>
|
||||
<%= link_to t("layouts.header.more_information"), page_path('more_information'), class: ("active" if current_page?("/more_information")) %>
|
||||
<%= link_to t("layouts.header.external_link_blog_url"), target: "_blank" do %>
|
||||
<%= t("layouts.header.external_link_blog") %>
|
||||
<small><i class="icon-external"></i></small>
|
||||
<% end %>
|
||||
<%= link_to t("layouts.header.debates"), debates_path, class: ("active" if controller_name == "debates") %>
|
||||
<%= link_to t("layouts.header.proposals"), proposals_path, class: ("active" if controller_name == "proposals") %>
|
||||
<%= link_to t("layouts.header.spending_proposals"), spending_proposals_path, class: ("active" if controller_name == "spending_proposals") %>
|
||||
<%= link_to t("layouts.header.more_information"), page_path('more_information'), class: ("active" if current_page?("/more_information")) %>
|
||||
<%= link_to t("layouts.header.external_link_blog_url"), target: "_blank" do %>
|
||||
<%= t("layouts.header.external_link_blog") %>
|
||||
<small><i class="icon-external"></i></small>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="small-12 medium-3 column">
|
||||
<%= yield :header_addon %>
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
</head>
|
||||
|
||||
<body class="auth-page">
|
||||
<div class="wrapper">
|
||||
<div class="wrapper margin-top">
|
||||
<div class="row">
|
||||
<div class="small-12 medium-8 large-5 column small-centered">
|
||||
<div class="small-12 medium-8 large-5 column small-centered margin-top">
|
||||
<h1>
|
||||
<%= link_to root_path do %>
|
||||
<%= image_tag('header_logo_madrid.png', class: 'show-for-medium-up left', size: '96x96', alt: t("layouts.header.logo")) %>
|
||||
|
||||
9
app/views/notifications/_notification.html.erb
Normal file
9
app/views/notifications/_notification.html.erb
Normal file
@@ -0,0 +1,9 @@
|
||||
<li id="<%= dom_id(notification) %>" class="notification">
|
||||
<%= link_to notification do %>
|
||||
<p>
|
||||
<em><%= t("notifications.index.#{notification_action(notification)}", count: notification.counter) %></em>
|
||||
<strong><%= notification.notifiable.is_a?(Comment) ? notification.notifiable.commentable.title : notification.notifiable.title %></strong>
|
||||
</p>
|
||||
<p class="time"><%= l notification.timestamp, format: :datetime %></p>
|
||||
<% end %>
|
||||
</li>
|
||||
21
app/views/notifications/index.html.erb
Normal file
21
app/views/notifications/index.html.erb
Normal file
@@ -0,0 +1,21 @@
|
||||
<div class="row">
|
||||
<div class="small-12 column">
|
||||
|
||||
<h1 class="left margin-top"><%= t("notifications.index.title") %></h1>
|
||||
|
||||
<% if @notifications.empty? %>
|
||||
<div class="alert-box radius info margin-top clear">
|
||||
<%= t("notifications.index.empty_notifications") %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="right margin-top">
|
||||
<%= link_to t("notifications.index.mark_all_as_read"),
|
||||
mark_all_as_read_notifications_path, method: :put %>
|
||||
</div>
|
||||
|
||||
<ul class="no-bullet clear notifications-list">
|
||||
<%= render @notifications %>
|
||||
</ul>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -29,6 +29,12 @@
|
||||
<% end %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to page_path('spending_proposals_info') do %>
|
||||
<%= t('pages.more_information.titles.spending_proposals_info') %>
|
||||
<span><%= t('pages.more_information.description.spending_proposals_info') %></span>
|
||||
<% end %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to page_path('participation_world') do %>
|
||||
<%= t('pages.more_information.titles.participation_world') %>
|
||||
<span><%= t('pages.more_information.description.participation_world') %></span>
|
||||
|
||||
20
app/views/pages/spending_proposals_info.html.erb
Normal file
20
app/views/pages/spending_proposals_info.html.erb
Normal file
@@ -0,0 +1,20 @@
|
||||
<div class="page row-full">
|
||||
<div class="row">
|
||||
<div class="menu small-12 medium-3 column">
|
||||
<i class="icon-angle-left left"></i>
|
||||
<%= link_to t("spending_proposals.new.back_link"), "/more_information", class: 'left back' %>
|
||||
<ul class="clear">
|
||||
<li>
|
||||
<a href="#i">Explicación detallada del proceso</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="text small-12 medium-9 column">
|
||||
<h1>¿Cómo funcionan los presupuestos ciudadanos?</h1>
|
||||
|
||||
<h2 id="i">Explicación detallada del proceso</h2>
|
||||
<p>Próximamente se podrá encontrar aquí una descripción del proceso de participación ciudadana en los presupuestos.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,22 +1,18 @@
|
||||
<div id="<%= dom_id(proposal) %>" class="proposal-featured small-12 column">
|
||||
<div class="panel">
|
||||
<div class="content small-12 medium-9 left">
|
||||
<h3><%= link_to proposal.title, proposal %></h3>
|
||||
<div class="info">
|
||||
<span class="author">
|
||||
<% if proposal.author.hidden? || proposal.author.erased? %>
|
||||
<%= t("proposals.show.author_deleted") %>
|
||||
<% else %>
|
||||
<%= proposal.author.name %>
|
||||
<% end %>
|
||||
</span>
|
||||
<span> • </span>
|
||||
<%= t("proposals.proposal.supports", count: proposal.total_votes) %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="<%= dom_id(proposal) %>_votes" class="small-12 medium-3 left">
|
||||
<%= render 'featured_votes', proposal: proposal %>
|
||||
<div id="<%= dom_id(proposal) %>" class="proposal-featured clear">
|
||||
<div class="small-12 medium-9 column">
|
||||
<h3><%= link_to proposal.title, proposal %></h3>
|
||||
<div class="info">
|
||||
<% if proposal.author.hidden? || proposal.author.erased? %>
|
||||
<%= t("proposals.show.author_deleted") %>
|
||||
<% else %>
|
||||
<%= proposal.author.name %>
|
||||
<% end %>
|
||||
•
|
||||
<strong><%= t("proposals.proposal.supports", count: proposal.total_votes) %></strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="<%= dom_id(proposal) %>_votes" class="small-12 medium-3 column">
|
||||
<%= render 'featured_votes', proposal: proposal %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -86,5 +86,3 @@
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
||||
@@ -9,48 +9,41 @@
|
||||
<div class="wrap row">
|
||||
<div id="proposals" class="proposals-list small-12 medium-9 column">
|
||||
|
||||
<div class="filters">
|
||||
<div class="small-12 medium-7 left">
|
||||
<% if @search_terms %>
|
||||
<h2 class="margin-top">
|
||||
<%= page_entries_info @proposals %>
|
||||
<%= t("proposals.index.search_results", count: @proposals.size, search_term: @search_terms) %>
|
||||
</h2>
|
||||
<% elsif @tag_filter %>
|
||||
<h2 class="margin-top">
|
||||
<%= page_entries_info @proposals %>
|
||||
<%= t("proposals.index.filter_topic", count: @proposals.size, topic: @tag_filter) %>
|
||||
<div class="small-12 medium-7 left">
|
||||
<% if @search_terms %>
|
||||
<h2 class="margin-top">
|
||||
<%= page_entries_info @proposals %>
|
||||
<%= t("proposals.index.search_results", count: @proposals.size, search_term: @search_terms) %>
|
||||
</h2>
|
||||
<% elsif @tag_filter %>
|
||||
<h2 class="margin-top">
|
||||
<%= page_entries_info @proposals %>
|
||||
<%= t("proposals.index.filter_topic", count: @proposals.size, topic: @tag_filter) %>
|
||||
</h2>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if @featured_proposals.present? %>
|
||||
<div id="featured-proposals" class="row featured-proposals">
|
||||
<div class="small-12 column">
|
||||
<h2>
|
||||
<%= t("proposals.index.featured_proposals") %>
|
||||
</h2>
|
||||
</div>
|
||||
<% @featured_proposals.each do |featured_proposal| %>
|
||||
<%= render "featured_proposal", proposal: featured_proposal %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if @featured_proposals.present? %>
|
||||
<div id="featured-proposals" class="row featured-proposals-container">
|
||||
<div class="small-12 medium-3 column">
|
||||
<h2>
|
||||
<%= t("proposals.index.featured_proposals_html") %>
|
||||
</h2>
|
||||
<span class="show-for-medium-up">
|
||||
<%= image_tag("featured_proposals.jpg", size: "210x135") %>
|
||||
</span>
|
||||
</div>
|
||||
<div class="small-12 medium-9 column proposals-list">
|
||||
<% @featured_proposals.each do |featured_proposal| %>
|
||||
<%= render "featured_proposal", proposal: featured_proposal %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= render 'shared/order_links', i18n_namespace: "proposals.index" %>
|
||||
|
||||
<%= render 'shared/order_links', i18n_namespace: "proposals.index" %>
|
||||
|
||||
<div class="show-for-small-only">
|
||||
<%= link_to t("proposals.index.start_proposal"), new_proposal_path, class: 'button radius expand' %>
|
||||
</div>
|
||||
|
||||
<%= render partial: 'proposals/proposal', collection: @proposals %>
|
||||
<%= paginate @proposals %>
|
||||
<div class="show-for-small-only">
|
||||
<%= link_to t("proposals.index.start_proposal"), new_proposal_path, class: 'button radius expand' %>
|
||||
</div>
|
||||
|
||||
<%= render partial: 'proposals/proposal', collection: @proposals %>
|
||||
<%= paginate @proposals %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-3 column">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<% if local_assigns[:message].present? %>
|
||||
<%= message %>
|
||||
<% else %>
|
||||
<%= t("form.not_saved", resource: t("form.#{resource.class.to_s.downcase}")) %>
|
||||
<%= t("form.not_saved", resource: t("form.#{resource.class.to_s.underscore}")) %>
|
||||
<% end %>
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
%>
|
||||
|
||||
<dl class="sub-nav">
|
||||
<dt><%= t("#{i18n_namespace}.filter") %>: </dt>
|
||||
<dt class="sr-only"><%= t("#{i18n_namespace}.filter") %>: </dt>
|
||||
|
||||
<% @valid_filters.each do |filter| %>
|
||||
<% if @current_filter == filter %>
|
||||
|
||||
46
app/views/spending_proposals/_form.html.erb
Normal file
46
app/views/spending_proposals/_form.html.erb
Normal file
@@ -0,0 +1,46 @@
|
||||
<%= form_for(@spending_proposal, url: form_url) do |f| %>
|
||||
<%= render 'shared/errors', resource: @spending_proposal %>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-12 column">
|
||||
<%= f.label :title, t("spending_proposals.form.title") %>
|
||||
<%= f.text_field :title, maxlength: SpendingProposal.title_max_length, placeholder: t("spending_proposals.form.title"), label: false %>
|
||||
</div>
|
||||
|
||||
<div class="ckeditor small-12 column">
|
||||
<%= f.label :description, t("spending_proposals.form.description") %>
|
||||
<%= f.cktext_area :description, maxlength: SpendingProposal.description_max_length, ckeditor: { language: I18n.locale }, label: false %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 column">
|
||||
<%= f.label :external_url, t("spending_proposals.form.external_url") %>
|
||||
<%= f.text_field :external_url, placeholder: t("spending_proposals.form.external_url"), label: false %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 column">
|
||||
<%= f.label :geozone_id, t("spending_proposals.form.geozone") %>
|
||||
<%= f.select :geozone_id, geozone_select_options, {include_blank: t("geozones.none"), label: false} %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 column">
|
||||
<% if @spending_proposal.new_record? %>
|
||||
<%= f.label :terms_of_service do %>
|
||||
<%= f.check_box :terms_of_service, label: false %>
|
||||
<span class="checkbox">
|
||||
<%= t("form.accept_terms",
|
||||
policy: link_to(t("form.policy"), "/privacy", target: "blank"),
|
||||
conditions: link_to(t("form.conditions"), "/conditions", target: "blank")).html_safe %>
|
||||
</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 column">
|
||||
<%= f.simple_captcha input_html: { required: false } %>
|
||||
</div>
|
||||
|
||||
<div class="actions small-12 column">
|
||||
<%= f.submit(class: "button radius", value: t("spending_proposals.form.submit_buttons.#{action_name}")) %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
16
app/views/spending_proposals/index.html.erb
Normal file
16
app/views/spending_proposals/index.html.erb
Normal file
@@ -0,0 +1,16 @@
|
||||
<% provide :title do %><%= t('spending_proposals.index.title') %><% end %>
|
||||
<div class="page row-full">
|
||||
<div class="row">
|
||||
<div class="more-information text small-12 medium-8 column">
|
||||
<h1><%= t('spending_proposals.index.title') %></h1>
|
||||
|
||||
<p><%= t('spending_proposals.index.text') %></p>
|
||||
|
||||
<% if can? :create, SpendingProposal %>
|
||||
<%= link_to t('spending_proposals.index.create_link'), new_spending_proposal_path, class: 'button radius' %>
|
||||
<% else %>
|
||||
<p><%= t('spending_proposals.index.verified_only', verify_account: link_to(t('spending_proposals.index.verify_account'), verification_path)).html_safe %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
27
app/views/spending_proposals/new.html.erb
Normal file
27
app/views/spending_proposals/new.html.erb
Normal file
@@ -0,0 +1,27 @@
|
||||
<div class="spending-proposal-new row">
|
||||
|
||||
<div class="small-12 medium-9 column">
|
||||
<%= link_to spending_proposals_path, class: "left back" do %>
|
||||
<i class="icon-angle-left left"></i>
|
||||
<%= t("spending_proposals.new.back_link") %>
|
||||
<% end %>
|
||||
<h1><%= t("spending_proposals.new.start_new") %></h1>
|
||||
<div class="alert-box info radius">
|
||||
<%= link_to "/spending_proposals_info", target: "_blank" do %>
|
||||
<%= t("spending_proposals.new.more_info")%>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= render "spending_proposals/form", form_url: spending_proposals_url %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-3 column">
|
||||
<i class="icon-spending-proposals right"></i>
|
||||
<h2><%= t("spending_proposals.new.recommendations_title") %></h2>
|
||||
<ul class="recommendations">
|
||||
<li><%= t("spending_proposals.new.recommendation_one") %></li>
|
||||
<li><%= t("spending_proposals.new.recommendation_two") %></li>
|
||||
<li><%= t("spending_proposals.new.recommendation_three") %></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,5 +1,5 @@
|
||||
<section role="main">
|
||||
<div class="activity row">
|
||||
<div class="activity row margin-top">
|
||||
<div class="small-12 column">
|
||||
|
||||
<h2>
|
||||
|
||||
@@ -4,19 +4,16 @@
|
||||
<div class="wrap row">
|
||||
<div id="activities" class="debates-list small-12 medium-9 column">
|
||||
|
||||
<div class="filters">
|
||||
|
||||
<div class="small-12 medium-7 left">
|
||||
<h1 class="inline-block"><%= t('welcome.highlights') %></h1>
|
||||
|
||||
<h2 class="margin-top">
|
||||
<%= t('welcome.signed_in_home_title') %>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<%= render @list %>
|
||||
<%= paginate @paginator %>
|
||||
<div class="small-12 medium-7 left">
|
||||
<h1 class="inline-block"><%= t('welcome.highlights') %></h1>
|
||||
|
||||
<h2 class="margin-top">
|
||||
<%= t('welcome.signed_in_home_title') %>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<%= render @list %>
|
||||
<%= paginate @paginator %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-3 column">
|
||||
|
||||
@@ -109,6 +109,7 @@ ignore_unused:
|
||||
- 'admin.comments.index.filter*'
|
||||
- 'admin.debates.index.filter*'
|
||||
- 'admin.proposals.index.filter*'
|
||||
- 'admin.spending_proposals.index.filter*'
|
||||
- 'admin.organizations.index.filter*'
|
||||
- 'admin.users.index.filter*'
|
||||
- 'admin.activity.show.filter*'
|
||||
@@ -127,6 +128,8 @@ ignore_unused:
|
||||
- 'proposals.index.select_order'
|
||||
- 'proposals.index.orders.*'
|
||||
- 'proposals.index.search_form.*'
|
||||
- 'notifications.index.comments_on*'
|
||||
- 'notifications.index.replies_to*'
|
||||
- 'helpers.page_entries_info.*' # kaminari
|
||||
- 'views.pagination.*' # kaminari
|
||||
# - '{devise,kaminari,will_paginate}.*'
|
||||
|
||||
@@ -37,6 +37,9 @@ en:
|
||||
proposal:
|
||||
one: "Citizen proposal"
|
||||
other: "Citizen proposals"
|
||||
spending_proposal:
|
||||
one: "Spending proposal"
|
||||
other: "Spending proposals"
|
||||
attributes:
|
||||
comment:
|
||||
body: "Comment"
|
||||
|
||||
@@ -37,6 +37,9 @@ es:
|
||||
proposal:
|
||||
one: "Propuesta ciudadana"
|
||||
other: "Propuestas ciudadanas"
|
||||
spending_proposal:
|
||||
one: "Propuesta de gasto"
|
||||
other: "Propuestas de gasto"
|
||||
attributes:
|
||||
comment:
|
||||
body: "Comentario"
|
||||
|
||||
@@ -16,6 +16,7 @@ en:
|
||||
hidden_debates: "Hidden debates"
|
||||
hidden_comments: "Hidden comments"
|
||||
hidden_users: "Hidden users"
|
||||
spending_proposals: "Spending proposals"
|
||||
incomplete_verifications: "Incomplete verifications"
|
||||
organizations: "Organisations"
|
||||
officials: "Officials"
|
||||
@@ -95,6 +96,20 @@ en:
|
||||
all: "All"
|
||||
with_confirmed_hide: "Confirmed"
|
||||
without_confirmed_hide: "Pending"
|
||||
spending_proposals:
|
||||
actions:
|
||||
accept: Accept
|
||||
reject: Reject
|
||||
index:
|
||||
title: "Spending proposals for participatory budgeting"
|
||||
filter: "Filter"
|
||||
filters:
|
||||
unresolved: "Unresolved"
|
||||
accepted: "Accepted"
|
||||
rejected: "Rejected"
|
||||
show:
|
||||
geozone: "Scope"
|
||||
by: "Sent by"
|
||||
users:
|
||||
index:
|
||||
title: "Hidden users"
|
||||
|
||||
@@ -16,6 +16,7 @@ es:
|
||||
hidden_debates: "Debates ocultos"
|
||||
hidden_comments: "Comentarios ocultos"
|
||||
hidden_users: "Usuarios bloqueados"
|
||||
spending_proposals: "Propuestas de gasto"
|
||||
incomplete_verifications: "Verificaciones incompletas"
|
||||
organizations: "Organizaciones"
|
||||
officials: "Cargos públicos"
|
||||
@@ -95,6 +96,20 @@ es:
|
||||
all: "Todas"
|
||||
with_confirmed_hide: "Confirmadas"
|
||||
without_confirmed_hide: "Pendientes"
|
||||
spending_proposals:
|
||||
actions:
|
||||
accept: Aceptar
|
||||
reject: Rechazar
|
||||
index:
|
||||
title: "Propuestas de gasto para presupuestos participativos"
|
||||
filter: "Filtro"
|
||||
filters:
|
||||
unresolved: "Sin resolver"
|
||||
accepted: "Aceptadas"
|
||||
rejected: "Rechazadas"
|
||||
show:
|
||||
geozone: "Ámbito"
|
||||
by: "Enviada por"
|
||||
users:
|
||||
index:
|
||||
title: "Usuarios bloqueados"
|
||||
|
||||
@@ -29,6 +29,11 @@ en:
|
||||
more_information: "More information"
|
||||
debates: "Debates"
|
||||
proposals: "Proposals"
|
||||
spending_proposals: "Spending proposals"
|
||||
new_notifications:
|
||||
one: "You have a new notification"
|
||||
other: "You have %{count} new notifications"
|
||||
no_notifications: "You don't have new notifications"
|
||||
footer:
|
||||
description: "This portal uses the %{consul} which is %{open_source}. From Madrid out into the world."
|
||||
open_source: "open-source software"
|
||||
@@ -71,6 +76,7 @@ en:
|
||||
user: "Account"
|
||||
debate: "Debate"
|
||||
proposal: "Proposal"
|
||||
spending_proposal: "Spending proposal"
|
||||
verification::sms: "Telephone"
|
||||
verification::letter: "the verification"
|
||||
application:
|
||||
@@ -79,7 +85,7 @@ en:
|
||||
debates:
|
||||
index:
|
||||
title: "Debates"
|
||||
featured_debates_html: "Featured<br>debates"
|
||||
featured_debates: "Featured"
|
||||
start_debate: "Start a debate"
|
||||
select_order: "Order by"
|
||||
orders:
|
||||
@@ -156,7 +162,7 @@ en:
|
||||
proposals:
|
||||
index:
|
||||
title: "Proposals"
|
||||
featured_proposals_html: "Featured<br>proposals"
|
||||
featured_proposals: "Featured"
|
||||
start_proposal: "Create a proposal"
|
||||
select_order_long: "You are viewing proposals according to:"
|
||||
select_order: "Order by"
|
||||
@@ -244,7 +250,34 @@ en:
|
||||
update:
|
||||
form:
|
||||
submit_button: "Save changes"
|
||||
spending_proposals:
|
||||
index:
|
||||
title: "Participatory budgeting"
|
||||
text: "Here you can send spending proposals to be considered in the frame of the annual participatory budgeting."
|
||||
create_link: "Create spending proposal"
|
||||
verified_only: "Only verified users can create spending proposals, %{verify_account}."
|
||||
verify_account: "verify your account"
|
||||
new:
|
||||
back_link: Back
|
||||
start_new: "Create spending proposal"
|
||||
more_info: "How do participatory budgeting works?"
|
||||
recommendations_title: "Recommendations for creating a spending proposal"
|
||||
recommendation_one: "It's mandatory that the proposal makes reference to a budgetable action."
|
||||
recommendation_two: "Any proposal or comment suggesting illegal action will be deleted."
|
||||
recommendation_three: "Try to go into details when describing your spending proposal so the reviewing team undertands your points."
|
||||
form:
|
||||
title: "Spending proposal title"
|
||||
description: "Description"
|
||||
external_url: "Link to additional documentation"
|
||||
geozone: "Scope of operation"
|
||||
submit_buttons:
|
||||
new: Create
|
||||
create: Create
|
||||
geozones:
|
||||
none: "All city"
|
||||
comments:
|
||||
show:
|
||||
return_to_commentable: "Go back to "
|
||||
select_order: "Sort by"
|
||||
orders:
|
||||
most_voted: "Most voted"
|
||||
@@ -311,6 +344,17 @@ en:
|
||||
user_permission_votes: "Participate on final voting"
|
||||
user_permission_verify: "To perform all the actions verify your account."
|
||||
user_permission_verify_info: "* Only for users on Madrid City Census."
|
||||
notifications:
|
||||
index:
|
||||
title: "Notifications"
|
||||
mark_all_as_read: "Mark all as read"
|
||||
empty_notifications: "You don't have new notifications."
|
||||
comments_on:
|
||||
one: "Someone commented on"
|
||||
other: "There are %{count} new comments on"
|
||||
replies_to:
|
||||
one: "Someone replied to your comment on"
|
||||
other: "There are %{count} new replies to your comment on"
|
||||
simple_captcha:
|
||||
placeholder: "Enter the text from the image"
|
||||
label: "Enter the text from the image in the box below"
|
||||
@@ -319,6 +363,7 @@ en:
|
||||
user: "the secret code does not match the image"
|
||||
debate: "the secret code does not match the image"
|
||||
proposal: "the secret code does not match the image"
|
||||
spendingproposal: "the secret code does not match the image"
|
||||
shared:
|
||||
author_info:
|
||||
author_deleted: "User deleted"
|
||||
|
||||
@@ -29,6 +29,11 @@ es:
|
||||
more_information: "Más información"
|
||||
debates: "Debates"
|
||||
proposals: "Propuestas"
|
||||
spending_proposals: "Presupuestos ciudadanos"
|
||||
new_notifications:
|
||||
one: "Tienes una nueva notificación"
|
||||
other: "Tienes %{count} notificaciones nuevas"
|
||||
no_notifications: "No tienes notificaciones nuevas"
|
||||
footer:
|
||||
description: "Este portal usa la %{consul} que es %{open_source}. De Madrid, para el mundo entero."
|
||||
open_source: "software libre"
|
||||
@@ -71,6 +76,7 @@ es:
|
||||
user: "la cuenta"
|
||||
debate: "el debate"
|
||||
proposal: "la propuesta"
|
||||
spending_proposal: "la propuesta de gasto"
|
||||
verification::sms: "el teléfono"
|
||||
verification::letter: "la verificación"
|
||||
application:
|
||||
@@ -79,7 +85,7 @@ es:
|
||||
debates:
|
||||
index:
|
||||
title: "Debates"
|
||||
featured_debates_html: "Debates<br>destacados"
|
||||
featured_debates: "Destacados"
|
||||
start_debate: "Empieza un debate"
|
||||
select_order: "Ordenar por"
|
||||
orders:
|
||||
@@ -156,7 +162,7 @@ es:
|
||||
proposals:
|
||||
index:
|
||||
title: "Propuestas ciudadanas"
|
||||
featured_proposals_html: "Propuestas<br>destacadas"
|
||||
featured_proposals: "Destacadas"
|
||||
start_proposal: "Crea una propuesta"
|
||||
select_order_long: "Estas viendo las propuestas"
|
||||
select_order: "Ordenar por"
|
||||
@@ -205,7 +211,7 @@ es:
|
||||
proposal_responsible_name: "Nombre y apellidos de la persona que hace esta propuesta"
|
||||
proposal_responsible_name_note: "(individualmente o como representante de un colectivo; no se mostrará públicamente)"
|
||||
tags_label: "Temas"
|
||||
tags_instructions: "Etiqueta esta propuesta. Puedes elegir entre Categorias y Distritos propuestos o introducir las que desees."
|
||||
tags_instructions: "Etiqueta esta propuesta. Puedes elegir entre nuestras sugerencias o introducir las que desees."
|
||||
tags_placeholder: "Escribe las etiquetas que desees separadas por una coma (',')"
|
||||
tag_category_label: "Categorías"
|
||||
tag_district_label: "Distritos"
|
||||
@@ -244,7 +250,34 @@ es:
|
||||
update:
|
||||
form:
|
||||
submit_button: "Guardar cambios"
|
||||
spending_proposals:
|
||||
index:
|
||||
title: "Presupuestos participativos"
|
||||
text: "Desde esta sección podrás sugerir propuestas de gasto que irán asociadas a las partidas de presupuestos ciudadanos. El requisito principal es que sean propuestas presupuestables."
|
||||
create_link: "Enviar propuesta de gasto"
|
||||
verified_only: "Sólo los usuarios verificados pueden crear propuestas de gasto, %{verify_account}."
|
||||
verify_account: "verifica tu cuenta"
|
||||
new:
|
||||
back_link: Volver
|
||||
start_new: "Crear una propuesta de gasto"
|
||||
more_info: "¿Cómo funcionan los presupuestos participativos?"
|
||||
recommendations_title: "Recomendaciones para crear una propuesta de gasto"
|
||||
recommendation_one: "Es fundamental que haga referencia a una actuación presupuestable."
|
||||
recommendation_two: "Cualquier propuesta o comentario que implique acciones ilegales será eliminada."
|
||||
recommendation_three: "Intenta detallar lo máximo posible la propuesta para que el equipo de gobierno encargado de estudiarla tenga las menor dudas posibles."
|
||||
form:
|
||||
title: "Título de la propuesta de gasto"
|
||||
description: "Descripción detallada"
|
||||
external_url: "Enlace a documentación adicional"
|
||||
geozone: "Ámbito de actuación"
|
||||
submit_buttons:
|
||||
new: Crear
|
||||
create: Crear
|
||||
geozones:
|
||||
none: "Toda la ciudad"
|
||||
comments:
|
||||
show:
|
||||
return_to_commentable: "Volver a "
|
||||
select_order: "Ordenar por"
|
||||
orders:
|
||||
most_voted: "Más votados"
|
||||
@@ -311,6 +344,17 @@ es:
|
||||
user_permission_votes: "Participar en las votaciones finales*"
|
||||
user_permission_verify: "Para poder realizar todas las acciones verifica tu cuenta."
|
||||
user_permission_verify_info: "* Sólo usuarios empadronados en el municipio de Madrid."
|
||||
notifications:
|
||||
index:
|
||||
title: "Notificaciones"
|
||||
mark_all_as_read: "Marcar todas como leídas"
|
||||
empty_notifications: "No tienes notificaciones nuevas."
|
||||
comments_on:
|
||||
one: "Hay un nuevo comentario en"
|
||||
other: "Hay %{count} comentarios nuevos en"
|
||||
replies_to:
|
||||
one: "Hay una respuesta nueva a tu comentario en"
|
||||
other: "Hay %{count} nuevas respuestas a tu comentario en"
|
||||
simple_captcha:
|
||||
placeholder: "Introduce el texto de la imagen"
|
||||
label: "Introduce el texto de la imagen en la siguiente caja"
|
||||
@@ -319,6 +363,7 @@ es:
|
||||
user: "el código secreto no coincide con la imagen"
|
||||
debate: "el código secreto no coincide con la imagen"
|
||||
proposal: "el código secreto no coincide con la imagen"
|
||||
spendingproposal: "el código secreto no coincide con la imagen"
|
||||
shared:
|
||||
author_info:
|
||||
author_deleted: Usuario eliminado
|
||||
|
||||
@@ -35,6 +35,7 @@ en:
|
||||
how_to_use: "Use it in your local government"
|
||||
participation: "Madrid Participation and Transparency y Transparencia - coming news"
|
||||
proposals_info: "How does citizen proposals work?"
|
||||
spending_proposals_info: "How does participatory budgeting work?"
|
||||
participation_world: "Direct citizen participation in the world"
|
||||
participation_facts: "Facts about citizen participation and direct democracy"
|
||||
faq: "Solution to tecnical problemas (FAQ)"
|
||||
@@ -44,6 +45,7 @@ en:
|
||||
how_to_use: "Use it freely or help us to improve it, it is free software"
|
||||
participation: "Citizen participation, transparency and open government"
|
||||
proposals_info: "Create your own proposals"
|
||||
spending_proposals_info: "Create your own spending proposals"
|
||||
participation_world: "Systems of citizen participation that exist in the world"
|
||||
participation_facts: "To lose your fear"
|
||||
faq: "Frecuently asked question about tecnical problems"
|
||||
|
||||
@@ -35,6 +35,7 @@ es:
|
||||
how_to_use: "Utilízalo en tu municipio"
|
||||
participation: "Participación y Transparencia en Madrid - Próximas novedades"
|
||||
proposals_info: "¿Cómo funcionan las propuestas ciudadanas?"
|
||||
spending_proposals_info: "¿Cómo funcionan los presupuestos participativos?"
|
||||
participation_world: "Participación ciudadana directa en el mundo"
|
||||
participation_facts: "Hechos sobre participación ciudadana y democracia directa"
|
||||
faq: "Soluciones a problemas técnicos (FAQ)"
|
||||
@@ -44,6 +45,7 @@ es:
|
||||
how_to_use: "Utilízalo libremente o ayúdanos a mejorarlo, es software libre"
|
||||
participation: "Participación Ciudadana, Transparencia y Gobierno Abierto"
|
||||
proposals_info: "Crea tus propias propuestas"
|
||||
spending_proposals_info: "Envía tus propuestas de gasto"
|
||||
participation_world: "Sistemas de participación ciudadana que ya existen en el mundo"
|
||||
participation_facts: "Para perderle el miedo"
|
||||
faq: "Preguntas frecuentes sobre problemas técnicos"
|
||||
|
||||
@@ -53,7 +53,7 @@ Rails.application.routes.draw do
|
||||
end
|
||||
end
|
||||
|
||||
resources :comments, only: :create, shallow: true do
|
||||
resources :comments, only: [:create, :show], shallow: true do
|
||||
member do
|
||||
post :vote
|
||||
put :flag
|
||||
@@ -61,6 +61,8 @@ Rails.application.routes.draw do
|
||||
end
|
||||
end
|
||||
|
||||
resources :spending_proposals, only: [:index, :new, :create]
|
||||
|
||||
resources :legislations, only: [:show]
|
||||
|
||||
resources :annotations do
|
||||
@@ -74,6 +76,11 @@ Rails.application.routes.draw do
|
||||
resource :account, controller: "account", only: [:show, :update, :delete] do
|
||||
collection { get :erase }
|
||||
end
|
||||
|
||||
resources :notifications, only: [:index, :show] do
|
||||
collection { put :mark_all_as_read }
|
||||
end
|
||||
|
||||
resource :verification, controller: "verification", only: [:show]
|
||||
|
||||
scope module: :verification do
|
||||
@@ -115,6 +122,13 @@ Rails.application.routes.draw do
|
||||
end
|
||||
end
|
||||
|
||||
resources :spending_proposals, only: [:index, :show] do
|
||||
member do
|
||||
put :accept
|
||||
put :reject
|
||||
end
|
||||
end
|
||||
|
||||
resources :comments, only: :index do
|
||||
member do
|
||||
put :restore
|
||||
|
||||
@@ -14,6 +14,9 @@ Setting.create(key: 'max_votes_for_proposal_edit', value: '1000')
|
||||
Setting.create(key: 'proposal_code_prefix', value: 'MAD')
|
||||
Setting.create(key: 'votes_for_proposal_success', value: '100')
|
||||
|
||||
puts "Creating Geozones"
|
||||
('A'..'Z').each{ |i| Geozone.create(name: "District #{i}") }
|
||||
|
||||
puts "Creating Users"
|
||||
|
||||
def create_user(email, username = Faker::Name.name)
|
||||
@@ -180,6 +183,25 @@ end
|
||||
Flag.flag(flagger, proposal)
|
||||
end
|
||||
|
||||
puts "Creating Spending Proposals"
|
||||
|
||||
resolutions = ["accepted", "rejected", nil]
|
||||
|
||||
(1..30).each do |i|
|
||||
geozone = Geozone.reorder("RANDOM()").first
|
||||
author = User.reorder("RANDOM()").first
|
||||
description = "<p>#{Faker::Lorem.paragraphs.join('</p><p>')}</p>"
|
||||
spending_proposal = SpendingProposal.create!(author: author,
|
||||
title: Faker::Lorem.sentence(3).truncate(60),
|
||||
external_url: Faker::Internet.url,
|
||||
description: description,
|
||||
created_at: rand((Time.now - 1.week) .. Time.now),
|
||||
resolution: resolutions.sample,
|
||||
geozone: [geozone, nil].sample,
|
||||
terms_of_service: "1")
|
||||
puts " #{spending_proposal.title}"
|
||||
end
|
||||
|
||||
puts "Creating Legislation"
|
||||
|
||||
Legislation.create!(title: 'Participatory Democracy', body: 'In order to achieve...')
|
||||
|
||||
9
db/migrate/20150928115005_create_notifications.rb
Normal file
9
db/migrate/20150928115005_create_notifications.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
class CreateNotifications < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :notifications do |t|
|
||||
t.belongs_to :user, index: true, foreign_key: true
|
||||
t.belongs_to :activity, index: true, foreign_key: true
|
||||
t.boolean :read, default: false
|
||||
end
|
||||
end
|
||||
end
|
||||
12
db/migrate/20151218114205_create_spending_proposals.rb
Normal file
12
db/migrate/20151218114205_create_spending_proposals.rb
Normal file
@@ -0,0 +1,12 @@
|
||||
class CreateSpendingProposals < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :spending_proposals do |t|
|
||||
t.string :title
|
||||
t.text :description
|
||||
t.integer :author_id
|
||||
t.string :external_url
|
||||
|
||||
t.timestamps null: false
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
class AddSpendingProposalsCounterToTags < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :tags, :spending_proposals_count, :integer, default: 0
|
||||
add_index :tags, :spending_proposals_count
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddSpendingProposalsIndexes < ActiveRecord::Migration
|
||||
def change
|
||||
add_index :spending_proposals, :author_id
|
||||
end
|
||||
end
|
||||
11
db/migrate/20160105121132_create_geozones.rb
Normal file
11
db/migrate/20160105121132_create_geozones.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
class CreateGeozones < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :geozones do |t|
|
||||
t.string :name
|
||||
t.string :html_map_coordinates
|
||||
t.string :external_code
|
||||
|
||||
t.timestamps null: false
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,10 @@
|
||||
class MergeActivitiesAndNotifications < ActiveRecord::Migration
|
||||
def change
|
||||
change_table :notifications do |t|
|
||||
t.remove :read
|
||||
t.remove :activity_id
|
||||
t.references :notifiable, polymorphic: true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
class AddGeozoneToSpendingProposal < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :spending_proposals, :geozone_id, :integer, default: nil
|
||||
add_index :spending_proposals, :geozone_id
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
class AddResolutionToSpendingProposals < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :spending_proposals, :resolution, :string, default: nil
|
||||
add_index :spending_proposals, :resolution
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddCounterToNotifications < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :notifications, :counter, :integer, default: 1
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddNotificationsCounterCacheToUser < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :users, :notifications_count, :integer, default: 0
|
||||
end
|
||||
end
|
||||
41
db/schema.rb
41
db/schema.rb
@@ -11,7 +11,8 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20160108101736) do
|
||||
|
||||
ActiveRecord::Schema.define(version: 20160108133501) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
@@ -171,6 +172,14 @@ ActiveRecord::Schema.define(version: 20160108101736) do
|
||||
add_index "flags", ["user_id", "flaggable_type", "flaggable_id"], name: "access_inappropiate_flags", using: :btree
|
||||
add_index "flags", ["user_id"], name: "index_flags_on_user_id", using: :btree
|
||||
|
||||
create_table "geozones", force: :cascade do |t|
|
||||
t.string "name"
|
||||
t.string "html_map_coordinates"
|
||||
t.string "external_code"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
create_table "identities", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
t.string "provider"
|
||||
@@ -191,7 +200,7 @@ ActiveRecord::Schema.define(version: 20160108101736) do
|
||||
create_table "locks", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
t.integer "tries", default: 0
|
||||
t.datetime "locked_until", default: '2000-01-01 07:01:01', null: false
|
||||
t.datetime "locked_until", default: '2000-01-01 00:01:01', null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
@@ -204,6 +213,15 @@ ActiveRecord::Schema.define(version: 20160108101736) do
|
||||
|
||||
add_index "moderators", ["user_id"], name: "index_moderators_on_user_id", using: :btree
|
||||
|
||||
create_table "notifications", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
t.integer "notifiable_id"
|
||||
t.string "notifiable_type"
|
||||
t.integer "counter", default: 1
|
||||
end
|
||||
|
||||
add_index "notifications", ["user_id"], name: "index_notifications_on_user_id", using: :btree
|
||||
|
||||
create_table "organizations", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
t.string "name", limit: 60
|
||||
@@ -264,6 +282,21 @@ ActiveRecord::Schema.define(version: 20160108101736) do
|
||||
|
||||
add_index "simple_captcha_data", ["key"], name: "idx_key", using: :btree
|
||||
|
||||
create_table "spending_proposals", force: :cascade do |t|
|
||||
t.string "title"
|
||||
t.text "description"
|
||||
t.integer "author_id"
|
||||
t.string "external_url"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.integer "geozone_id"
|
||||
t.string "resolution"
|
||||
end
|
||||
|
||||
add_index "spending_proposals", ["author_id"], name: "index_spending_proposals_on_author_id", using: :btree
|
||||
add_index "spending_proposals", ["geozone_id"], name: "index_spending_proposals_on_geozone_id", using: :btree
|
||||
add_index "spending_proposals", ["resolution"], name: "index_spending_proposals_on_resolution", using: :btree
|
||||
|
||||
create_table "taggings", force: :cascade do |t|
|
||||
t.integer "tag_id"
|
||||
t.integer "taggable_id"
|
||||
@@ -284,11 +317,13 @@ ActiveRecord::Schema.define(version: 20160108101736) do
|
||||
t.integer "debates_count", default: 0
|
||||
t.integer "proposals_count", default: 0
|
||||
t.string "kind", limit: 40
|
||||
t.integer "spending_proposals_count", default: 0
|
||||
end
|
||||
|
||||
add_index "tags", ["debates_count"], name: "index_tags_on_debates_count", using: :btree
|
||||
add_index "tags", ["name"], name: "index_tags_on_name", unique: true, using: :btree
|
||||
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 "users", force: :cascade do |t|
|
||||
t.string "email", default: ""
|
||||
@@ -331,6 +366,7 @@ ActiveRecord::Schema.define(version: 20160108101736) do
|
||||
t.datetime "erased_at"
|
||||
t.boolean "public_activity", default: true
|
||||
t.boolean "newsletter", default: false
|
||||
t.integer "notifications_count", default: 0
|
||||
end
|
||||
|
||||
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
|
||||
@@ -405,5 +441,6 @@ ActiveRecord::Schema.define(version: 20160108101736) do
|
||||
add_foreign_key "identities", "users"
|
||||
add_foreign_key "locks", "users"
|
||||
add_foreign_key "moderators", "users"
|
||||
add_foreign_key "notifications", "users"
|
||||
add_foreign_key "organizations", "users"
|
||||
end
|
||||
|
||||
@@ -2,24 +2,34 @@ class CommentTree
|
||||
|
||||
ROOT_COMMENTS_PER_PAGE = 10
|
||||
|
||||
attr_accessor :root_comments, :comments
|
||||
attr_accessor :root_comments, :comments, :commentable, :page, :order
|
||||
|
||||
def initialize(commentable, page, order = 'confidence_score')
|
||||
@root_comments = commentable.comments.roots.send("sort_by_#{order}").page(page).per(ROOT_COMMENTS_PER_PAGE).for_render
|
||||
|
||||
root_descendants = @root_comments.each_with_object([]) do |root, col|
|
||||
col.concat(Comment.descendants_of(root).send("sort_descendants_by_#{order}").for_render.to_a)
|
||||
end
|
||||
@commentable = commentable
|
||||
@page = page
|
||||
@order = order
|
||||
|
||||
@comments = root_comments + root_descendants
|
||||
end
|
||||
|
||||
@comments_by_parent_id = @comments.each_with_object({}) do |comment, col|
|
||||
(col[comment.parent_id] ||= []) << comment
|
||||
def root_comments
|
||||
commentable.comments.roots.send("sort_by_#{order}").page(page).per(ROOT_COMMENTS_PER_PAGE).for_render
|
||||
end
|
||||
|
||||
def root_descendants
|
||||
root_comments.each_with_object([]) do |root, array|
|
||||
array.concat(Comment.descendants_of(root).send("sort_descendants_by_#{order}").for_render.to_a)
|
||||
end
|
||||
end
|
||||
|
||||
def children_of(parent)
|
||||
@comments_by_parent_id[parent.id] || []
|
||||
def ordered_children_of(parent)
|
||||
comments_by_parent_id[parent.id] || []
|
||||
end
|
||||
|
||||
def comments_by_parent_id
|
||||
comments.each_with_object({}) do |comment, array|
|
||||
(array[comment.parent_id] ||= []) << comment
|
||||
end
|
||||
end
|
||||
|
||||
def comment_authors
|
||||
|
||||
@@ -180,6 +180,14 @@ FactoryGirl.define do
|
||||
end
|
||||
end
|
||||
|
||||
factory :spending_proposal do
|
||||
sequence(:title) { |n| "Spending Proposal #{n} title" }
|
||||
description 'Spend money on this'
|
||||
external_url 'http://external_documention.org'
|
||||
terms_of_service '1'
|
||||
association :author, factory: :user
|
||||
end
|
||||
|
||||
factory :vote do
|
||||
association :votable, factory: :debate
|
||||
association :voter, factory: :user
|
||||
@@ -291,4 +299,12 @@ FactoryGirl.define do
|
||||
sequence(:track_id) { |n| "#{n}" }
|
||||
end
|
||||
|
||||
factory :notification do
|
||||
user
|
||||
association :notifiable, factory: :proposal
|
||||
end
|
||||
|
||||
factory :geozone do
|
||||
sequence(:name) { |n| "District #{n}" }
|
||||
end
|
||||
end
|
||||
|
||||
140
spec/features/admin/spending_proposals_spec.rb
Normal file
140
spec/features/admin/spending_proposals_spec.rb
Normal file
@@ -0,0 +1,140 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Admin spending proposals' do
|
||||
|
||||
background do
|
||||
admin = create(:administrator)
|
||||
login_as(admin.user)
|
||||
end
|
||||
|
||||
scenario 'Index shows spending proposals' do
|
||||
spending_proposal = create(:spending_proposal)
|
||||
visit admin_spending_proposals_path
|
||||
|
||||
expect(page).to have_content(spending_proposal.title)
|
||||
end
|
||||
|
||||
scenario 'Accept from index' do
|
||||
spending_proposal = create(:spending_proposal)
|
||||
visit admin_spending_proposals_path
|
||||
|
||||
click_link 'Accept'
|
||||
|
||||
expect(page).to_not have_content(spending_proposal.title)
|
||||
|
||||
click_link 'Accepted'
|
||||
expect(page).to have_content(spending_proposal.title)
|
||||
|
||||
expect(spending_proposal.reload).to be_accepted
|
||||
end
|
||||
|
||||
scenario 'Reject from index' do
|
||||
spending_proposal = create(:spending_proposal)
|
||||
visit admin_spending_proposals_path
|
||||
|
||||
click_link 'Reject'
|
||||
|
||||
expect(page).to_not have_content(spending_proposal.title)
|
||||
|
||||
click_link('Rejected')
|
||||
expect(page).to have_content(spending_proposal.title)
|
||||
|
||||
expect(spending_proposal.reload).to be_rejected
|
||||
end
|
||||
|
||||
scenario "Current filter is properly highlighted" do
|
||||
visit admin_spending_proposals_path
|
||||
expect(page).to_not have_link('Unresolved')
|
||||
expect(page).to have_link('Accepted')
|
||||
expect(page).to have_link('Rejected')
|
||||
|
||||
visit admin_spending_proposals_path(filter: 'unresolved')
|
||||
expect(page).to_not have_link('Unresolved')
|
||||
expect(page).to have_link('Accepted')
|
||||
expect(page).to have_link('Rejected')
|
||||
|
||||
visit admin_spending_proposals_path(filter: 'accepted')
|
||||
expect(page).to have_link('Unresolved')
|
||||
expect(page).to_not have_link('Accepted')
|
||||
expect(page).to have_link('Rejected')
|
||||
|
||||
visit admin_spending_proposals_path(filter: 'rejected')
|
||||
expect(page).to have_link('Accepted')
|
||||
expect(page).to have_link('Unresolved')
|
||||
expect(page).to_not have_link('Rejected')
|
||||
end
|
||||
|
||||
scenario "Filtering proposals" do
|
||||
create(:spending_proposal, title: "Recent spending proposal")
|
||||
create(:spending_proposal, title: "Good spending proposal", resolution: "accepted")
|
||||
create(:spending_proposal, title: "Bad spending proposal", resolution: "rejected")
|
||||
|
||||
visit admin_spending_proposals_path(filter: 'unresolved')
|
||||
expect(page).to have_content('Recent spending proposal')
|
||||
expect(page).to_not have_content('Good spending proposal')
|
||||
expect(page).to_not have_content('Bad spending proposal')
|
||||
|
||||
visit admin_spending_proposals_path(filter: 'accepted')
|
||||
expect(page).to have_content('Good spending proposal')
|
||||
expect(page).to_not have_content('Recent spending proposal')
|
||||
expect(page).to_not have_content('Bad spending proposal')
|
||||
|
||||
visit admin_spending_proposals_path(filter: 'rejected')
|
||||
expect(page).to have_content('Bad spending proposal')
|
||||
expect(page).to_not have_content('Good spending proposal')
|
||||
expect(page).to_not have_content('Recent spending proposal')
|
||||
end
|
||||
|
||||
scenario "Action links remember the pagination setting and the filter" do
|
||||
per_page = Kaminari.config.default_per_page
|
||||
(per_page + 2).times { create(:spending_proposal, resolution: "accepted") }
|
||||
|
||||
visit admin_spending_proposals_path(filter: 'accepted', page: 2)
|
||||
|
||||
click_on('Reject', match: :first, exact: true)
|
||||
|
||||
expect(current_url).to include('filter=accepted')
|
||||
expect(current_url).to include('page=2')
|
||||
end
|
||||
|
||||
scenario 'Show' do
|
||||
spending_proposal = create(:spending_proposal, geozone: create(:geozone))
|
||||
visit admin_spending_proposals_path
|
||||
|
||||
click_link spending_proposal.title
|
||||
|
||||
expect(page).to have_content(spending_proposal.title)
|
||||
expect(page).to have_content(spending_proposal.description)
|
||||
expect(page).to have_content(spending_proposal.author.name)
|
||||
expect(page).to have_content(spending_proposal.geozone.name)
|
||||
end
|
||||
|
||||
scenario 'Accept from show' do
|
||||
spending_proposal = create(:spending_proposal)
|
||||
visit admin_spending_proposal_path(spending_proposal)
|
||||
|
||||
click_link 'Accept'
|
||||
|
||||
expect(page).to_not have_content(spending_proposal.title)
|
||||
|
||||
click_link 'Accepted'
|
||||
expect(page).to have_content(spending_proposal.title)
|
||||
|
||||
expect(spending_proposal.reload).to be_accepted
|
||||
end
|
||||
|
||||
scenario 'Reject from show' do
|
||||
spending_proposal = create(:spending_proposal)
|
||||
visit admin_spending_proposal_path(spending_proposal)
|
||||
|
||||
click_link 'Reject'
|
||||
|
||||
expect(page).to_not have_content(spending_proposal.title)
|
||||
|
||||
click_link('Rejected')
|
||||
expect(page).to have_content(spending_proposal.title)
|
||||
|
||||
expect(spending_proposal.reload).to be_rejected
|
||||
end
|
||||
|
||||
end
|
||||
@@ -20,6 +20,21 @@ feature 'Commenting debates' do
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Show' do
|
||||
parent_comment = create(:comment, commentable: debate)
|
||||
first_child = create(:comment, commentable: debate, parent: parent_comment)
|
||||
second_child = create(:comment, commentable: debate, 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 #{debate.title}", debate_path(debate)
|
||||
end
|
||||
|
||||
scenario 'Comment order' do
|
||||
c1 = create(:comment, :with_confidence_score, commentable: debate, cached_votes_up: 100, cached_votes_total: 120, created_at: Time.now - 2)
|
||||
c2 = create(:comment, :with_confidence_score, commentable: debate, cached_votes_up: 10, cached_votes_total: 12, created_at: Time.now - 1)
|
||||
@@ -254,7 +269,7 @@ feature 'Commenting debates' do
|
||||
|
||||
fill_in "comment-body-debate_#{debate.id}", with: 'Testing submit button!'
|
||||
click_button 'Publish comment'
|
||||
|
||||
|
||||
# The button's text should now be "..."
|
||||
# This should be checked before the Ajax request is finished
|
||||
expect(page).to_not have_button 'Publish comment'
|
||||
|
||||
@@ -20,6 +20,21 @@ feature 'Commenting proposals' do
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Show' do
|
||||
parent_comment = create(:comment, commentable: proposal)
|
||||
first_child = create(:comment, commentable: proposal, parent: parent_comment)
|
||||
second_child = create(:comment, commentable: proposal, 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 #{proposal.title}", proposal_path(proposal)
|
||||
end
|
||||
|
||||
scenario 'Comment order' do
|
||||
c1 = create(:comment, :with_confidence_score, commentable: proposal, cached_votes_up: 100, cached_votes_total: 120, created_at: Time.now - 2)
|
||||
c2 = create(:comment, :with_confidence_score, commentable: proposal, cached_votes_up: 10, cached_votes_total: 12, created_at: Time.now - 1)
|
||||
|
||||
192
spec/features/notifications_spec.rb
Normal file
192
spec/features/notifications_spec.rb
Normal file
@@ -0,0 +1,192 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "Notifications" do
|
||||
let(:author) { create :user }
|
||||
let(:user) { create :user }
|
||||
let(:debate) { create :debate, author: author }
|
||||
let(:proposal) { create :proposal, author: author }
|
||||
|
||||
scenario "User commented on my debate", :js do
|
||||
login_as user
|
||||
visit debate_path debate
|
||||
|
||||
fill_in "comment-body-debate_#{debate.id}", with: "I commented on your debate"
|
||||
click_button "Publish comment"
|
||||
within "#comments" do
|
||||
expect(page).to have_content "I commented on your debate"
|
||||
end
|
||||
|
||||
logout
|
||||
login_as author
|
||||
visit root_path
|
||||
|
||||
find(".icon-notification").click
|
||||
|
||||
expect(page).to have_css ".notification", count: 1
|
||||
|
||||
expect(page).to have_content "Someone commented on"
|
||||
expect(page).to have_xpath "//a[@href='#{notification_path(Notification.last)}']"
|
||||
end
|
||||
|
||||
scenario "Multiple comments on my proposal", :js do
|
||||
login_as user
|
||||
visit proposal_path proposal
|
||||
|
||||
fill_in "comment-body-proposal_#{proposal.id}", with: "I agree"
|
||||
click_button "Publish comment"
|
||||
within "#comments" do
|
||||
expect(page).to have_content "I agree"
|
||||
end
|
||||
|
||||
logout
|
||||
login_as create(:user)
|
||||
visit proposal_path proposal
|
||||
|
||||
fill_in "comment-body-proposal_#{proposal.id}", with: "I disagree"
|
||||
click_button "Publish comment"
|
||||
within "#comments" do
|
||||
expect(page).to have_content "I disagree"
|
||||
end
|
||||
|
||||
logout
|
||||
login_as author
|
||||
visit root_path
|
||||
|
||||
find(".icon-notification").click
|
||||
|
||||
expect(page).to have_css ".notification", count: 1
|
||||
|
||||
expect(page).to have_content "There are 2 new comments on"
|
||||
expect(page).to have_xpath "//a[@href='#{notification_path(Notification.last)}']"
|
||||
end
|
||||
|
||||
scenario "User replied to my comment", :js do
|
||||
comment = create :comment, commentable: debate, user: author
|
||||
login_as user
|
||||
visit debate_path debate
|
||||
|
||||
click_link "Reply"
|
||||
within "#js-comment-form-comment_#{comment.id}" do
|
||||
fill_in "comment-body-comment_#{comment.id}", with: "I replied to your comment"
|
||||
click_button "Publish reply"
|
||||
end
|
||||
|
||||
within "#comment_#{comment.id}" do
|
||||
expect(page).to have_content "I replied to your comment"
|
||||
end
|
||||
|
||||
logout
|
||||
login_as author
|
||||
visit root_path
|
||||
|
||||
find(".icon-notification").click
|
||||
|
||||
expect(page).to have_css ".notification", count: 1
|
||||
expect(page).to have_content "Someone replied to your comment on"
|
||||
expect(page).to have_xpath "//a[@href='#{notification_path(Notification.last)}']"
|
||||
end
|
||||
|
||||
scenario "Multiple replies to my comment", :js do
|
||||
comment = create :comment, commentable: debate, user: author
|
||||
3.times do |n|
|
||||
login_as create(:user)
|
||||
visit debate_path debate
|
||||
|
||||
within("#comment_#{comment.id}_reply") { click_link "Reply" }
|
||||
within "#js-comment-form-comment_#{comment.id}" do
|
||||
fill_in "comment-body-comment_#{comment.id}", with: "Reply number #{n}"
|
||||
click_button "Publish reply"
|
||||
end
|
||||
|
||||
within "#comment_#{comment.id}" do
|
||||
expect(page).to have_content "Reply number #{n}"
|
||||
end
|
||||
logout
|
||||
end
|
||||
|
||||
login_as author
|
||||
visit root_path
|
||||
|
||||
find(".icon-notification").click
|
||||
|
||||
expect(page).to have_css ".notification", count: 1
|
||||
expect(page).to have_content "There are 3 new replies to your comment on"
|
||||
expect(page).to have_xpath "//a[@href='#{notification_path(Notification.last)}']"
|
||||
end
|
||||
|
||||
scenario "Author commented on his own debate", :js do
|
||||
login_as author
|
||||
visit debate_path debate
|
||||
|
||||
fill_in "comment-body-debate_#{debate.id}", with: "I commented on my own debate"
|
||||
click_button "Publish comment"
|
||||
within "#comments" do
|
||||
expect(page).to have_content "I commented on my own debate"
|
||||
end
|
||||
|
||||
find(".icon-no-notification").click
|
||||
expect(page).to have_css ".notification", count: 0
|
||||
end
|
||||
|
||||
scenario "Author replied to his own comment", :js do
|
||||
comment = create :comment, commentable: debate, user: author
|
||||
login_as author
|
||||
visit debate_path debate
|
||||
|
||||
click_link "Reply"
|
||||
within "#js-comment-form-comment_#{comment.id}" do
|
||||
fill_in "comment-body-comment_#{comment.id}", with: "I replied to my own comment"
|
||||
click_button "Publish reply"
|
||||
end
|
||||
|
||||
within "#comment_#{comment.id}" do
|
||||
expect(page).to have_content "I replied to my own comment"
|
||||
end
|
||||
|
||||
find(".icon-no-notification")
|
||||
|
||||
visit notifications_path
|
||||
expect(page).to have_css ".notification", count: 0
|
||||
end
|
||||
|
||||
context "mark as read" do
|
||||
|
||||
scenario "mark a single notification as read" do
|
||||
user = create :user
|
||||
notification = create :notification, user: user
|
||||
|
||||
login_as user
|
||||
visit notifications_path
|
||||
|
||||
expect(page).to have_css ".notification", count: 1
|
||||
|
||||
first(".notification a").click
|
||||
visit notifications_path
|
||||
|
||||
expect(page).to have_css ".notification", count: 0
|
||||
end
|
||||
|
||||
scenario "mark all notifications as read" do
|
||||
user = create :user
|
||||
2.times { create :notification, user: user }
|
||||
|
||||
login_as user
|
||||
visit notifications_path
|
||||
|
||||
expect(page).to have_css ".notification", count: 2
|
||||
click_link "Mark all as read"
|
||||
|
||||
expect(page).to have_css ".notification", count: 0
|
||||
expect(current_path).to eq(notifications_path)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
scenario "no notifications" do
|
||||
login_as user
|
||||
visit notifications_path
|
||||
|
||||
expect(page).to have_content "You don't have new notifications"
|
||||
end
|
||||
|
||||
end
|
||||
66
spec/features/spending_proposals_spec.rb
Normal file
66
spec/features/spending_proposals_spec.rb
Normal file
@@ -0,0 +1,66 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Spending proposals' do
|
||||
|
||||
let(:author) { create(:user, :level_two) }
|
||||
|
||||
scenario 'Index' do
|
||||
visit spending_proposals_path
|
||||
|
||||
expect(page).to_not have_link('Create spending proposal', href: new_spending_proposal_path)
|
||||
expect(page).to have_link('verify your account')
|
||||
|
||||
login_as(author)
|
||||
|
||||
visit spending_proposals_path
|
||||
|
||||
expect(page).to have_link('Create spending proposal', href: new_spending_proposal_path)
|
||||
expect(page).to_not have_link('verify your account')
|
||||
end
|
||||
|
||||
scenario 'Create' do
|
||||
login_as(author)
|
||||
|
||||
visit new_spending_proposal_path
|
||||
fill_in 'spending_proposal_title', with: 'Build a skyscraper'
|
||||
fill_in 'spending_proposal_description', with: 'I want to live in a high tower over the clouds'
|
||||
fill_in 'spending_proposal_external_url', with: 'http://http://skyscraperpage.com/'
|
||||
fill_in 'spending_proposal_captcha', with: correct_captcha_text
|
||||
select 'All city', from: 'spending_proposal_geozone_id'
|
||||
check 'spending_proposal_terms_of_service'
|
||||
|
||||
click_button 'Create'
|
||||
|
||||
expect(page).to have_content 'Spending proposal created successfully'
|
||||
end
|
||||
|
||||
scenario 'Captcha is required for proposal creation' do
|
||||
login_as(author)
|
||||
|
||||
visit new_spending_proposal_path
|
||||
fill_in 'spending_proposal_title', with: 'Build a skyscraper'
|
||||
fill_in 'spending_proposal_description', with: 'I want to live in a high tower over the clouds'
|
||||
fill_in 'spending_proposal_external_url', with: 'http://http://skyscraperpage.com/'
|
||||
fill_in 'spending_proposal_captcha', with: 'wrongText'
|
||||
check 'spending_proposal_terms_of_service'
|
||||
|
||||
click_button 'Create'
|
||||
|
||||
expect(page).to_not have_content 'Spending proposal created successfully'
|
||||
expect(page).to have_content '1 error'
|
||||
|
||||
fill_in 'spending_proposal_captcha', with: correct_captcha_text
|
||||
click_button 'Create'
|
||||
|
||||
expect(page).to have_content 'Spending proposal created successfully'
|
||||
end
|
||||
|
||||
scenario 'Errors on create' do
|
||||
login_as(author)
|
||||
|
||||
visit new_spending_proposal_path
|
||||
click_button 'Create'
|
||||
expect(page).to have_content error_message
|
||||
end
|
||||
|
||||
end
|
||||
35
spec/helpers/geozones_helper_spec.rb
Normal file
35
spec/helpers/geozones_helper_spec.rb
Normal file
@@ -0,0 +1,35 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe GeozonesHelper do
|
||||
|
||||
describe "#geozones_name" do
|
||||
let(:geozone) { create :geozone }
|
||||
|
||||
|
||||
it "returns geozone name if present" do
|
||||
spending_proposal = create(:spending_proposal, geozone: geozone)
|
||||
expect(geozone_name(spending_proposal)).to eq geozone.name
|
||||
end
|
||||
|
||||
it "returns default string for no geozone if geozone is blank" do
|
||||
spending_proposal = create(:spending_proposal, geozone: nil)
|
||||
expect(geozone_name(spending_proposal)).to eq "All city"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#geozone_select_options" do
|
||||
it "returns array of ids and names ordered by name" do
|
||||
g1 = create(:geozone, name: "AAA")
|
||||
g3 = create(:geozone, name: "CCC")
|
||||
g2 = create(:geozone, name: "BBB")
|
||||
|
||||
select_options = geozone_select_options
|
||||
|
||||
expect(select_options.size).to eq 3
|
||||
expect(select_options.first).to eq [g1.name, g1.id]
|
||||
expect(select_options[1]).to eq [g2.name, g2.id]
|
||||
expect(select_options.last).to eq [g3.name, g3.id]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
25
spec/helpers/notifications_helper_spec.rb
Normal file
25
spec/helpers/notifications_helper_spec.rb
Normal file
@@ -0,0 +1,25 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe NotificationsHelper do
|
||||
|
||||
describe "#notification_action" do
|
||||
let(:debate) { create :debate }
|
||||
let(:debate_comment) { create :comment, commentable: debate }
|
||||
|
||||
context "when action was comment on a debate" do
|
||||
it "returns correct text when someone comments on your debate" do
|
||||
notification = create :notification, notifiable: debate
|
||||
expect(notification_action(notification)).to eq "comments_on"
|
||||
end
|
||||
end
|
||||
|
||||
context "when action was comment on a debate" do
|
||||
it "returns correct text when someone replies to your comment" do
|
||||
notification = create :notification, notifiable: debate_comment
|
||||
expect(notification_action(notification)).to eq "replies_to"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -51,4 +51,6 @@ describe "Abilities::Administrator" do
|
||||
it { should_not be_able_to(:comment_as_moderator, proposal) }
|
||||
|
||||
it { should be_able_to(:manage, Annotation) }
|
||||
|
||||
it { should be_able_to(:manage, SpendingProposal) }
|
||||
end
|
||||
|
||||
@@ -28,6 +28,9 @@ describe "Abilities::Common" do
|
||||
it { should_not be_able_to(:vote, Proposal) }
|
||||
it { should_not be_able_to(:vote_featured, Proposal) }
|
||||
|
||||
it { should be_able_to(:index, SpendingProposal) }
|
||||
it { should_not be_able_to(:create, SpendingProposal) }
|
||||
|
||||
it { should_not be_able_to(:comment_as_administrator, debate) }
|
||||
it { should_not be_able_to(:comment_as_moderator, debate) }
|
||||
it { should_not be_able_to(:comment_as_administrator, proposal) }
|
||||
@@ -84,6 +87,8 @@ describe "Abilities::Common" do
|
||||
|
||||
it { should be_able_to(:vote, Proposal) }
|
||||
it { should be_able_to(:vote_featured, Proposal) }
|
||||
|
||||
it { should be_able_to(:create, SpendingProposal) }
|
||||
end
|
||||
|
||||
describe "when level 3 verified" do
|
||||
@@ -91,5 +96,7 @@ describe "Abilities::Common" do
|
||||
|
||||
it { should be_able_to(:vote, Proposal) }
|
||||
it { should be_able_to(:vote_featured, Proposal) }
|
||||
|
||||
it { should be_able_to(:create, SpendingProposal) }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -21,4 +21,9 @@ describe "Abilities::Everyone" do
|
||||
it { should_not be_able_to(:vote, Proposal) }
|
||||
it { should_not be_able_to(:flag, Proposal) }
|
||||
it { should_not be_able_to(:unflag, Proposal) }
|
||||
|
||||
it { should be_able_to(:show, Comment) }
|
||||
|
||||
it { should be_able_to(:index, SpendingProposal) }
|
||||
it { should_not be_able_to(:create, SpendingProposal) }
|
||||
end
|
||||
|
||||
@@ -128,4 +128,5 @@ describe Comment do
|
||||
expect(Comment.not_as_admin_or_moderator.first).to eq(comment1)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
14
spec/models/geozone_spec.rb
Normal file
14
spec/models/geozone_spec.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Geozone, type: :model do
|
||||
let(:geozone) { build(:geozone) }
|
||||
|
||||
it "should be valid" do
|
||||
expect(geozone).to be_valid
|
||||
end
|
||||
|
||||
it "should not be valid without a name" do
|
||||
geozone.name = nil
|
||||
expect(geozone).to_not be_valid
|
||||
end
|
||||
end
|
||||
50
spec/models/notification_spec.rb
Normal file
50
spec/models/notification_spec.rb
Normal file
@@ -0,0 +1,50 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe Notification do
|
||||
|
||||
describe "#unread (scope)" do
|
||||
it "returns only unread notifications" do
|
||||
2.times { create :notification }
|
||||
expect(Notification.unread.size).to be 2
|
||||
end
|
||||
end
|
||||
|
||||
describe "#recent (scope)" do
|
||||
it "returns notifications sorted by id descendant" do
|
||||
old_notification = create :notification
|
||||
new_notification = create :notification
|
||||
|
||||
sorted_notifications = Notification.recent
|
||||
expect(sorted_notifications.size).to be 2
|
||||
expect(sorted_notifications.first).to eq new_notification
|
||||
expect(sorted_notifications.last).to eq old_notification
|
||||
end
|
||||
end
|
||||
|
||||
describe "#for_render (scope)" do
|
||||
it "returns notifications including notifiable and user" do
|
||||
expect(Notification).to receive(:includes).with(:notifiable).exactly(:once)
|
||||
Notification.for_render
|
||||
end
|
||||
end
|
||||
|
||||
describe "#timestamp" do
|
||||
it "returns the timestamp of the trackable object" do
|
||||
comment = create :comment
|
||||
notification = create :notification, notifiable: comment
|
||||
|
||||
expect(notification.timestamp).to eq comment.created_at
|
||||
end
|
||||
end
|
||||
|
||||
describe "#mark_as_read" do
|
||||
it "destroys notification" do
|
||||
notification = create :notification
|
||||
expect(Notification.unread.size).to eq 1
|
||||
|
||||
notification.mark_as_read
|
||||
expect(Notification.unread.size).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
140
spec/models/spending_proposal_spec.rb
Normal file
140
spec/models/spending_proposal_spec.rb
Normal file
@@ -0,0 +1,140 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe SpendingProposal do
|
||||
let(:spending_proposal) { build(:spending_proposal) }
|
||||
|
||||
it "should be valid" do
|
||||
expect(spending_proposal).to be_valid
|
||||
end
|
||||
|
||||
it "should not be valid without an author" do
|
||||
spending_proposal.author = nil
|
||||
expect(spending_proposal).to_not be_valid
|
||||
end
|
||||
|
||||
describe "#title" do
|
||||
it "should not be valid without a title" do
|
||||
spending_proposal.title = nil
|
||||
expect(spending_proposal).to_not be_valid
|
||||
end
|
||||
|
||||
it "should not be valid when very short" do
|
||||
spending_proposal.title = "abc"
|
||||
expect(spending_proposal).to_not be_valid
|
||||
end
|
||||
|
||||
it "should not be valid when very long" do
|
||||
spending_proposal.title = "a" * 81
|
||||
expect(spending_proposal).to_not be_valid
|
||||
end
|
||||
end
|
||||
|
||||
describe "#description" do
|
||||
it "should be sanitized" do
|
||||
spending_proposal.description = "<script>alert('danger');</script>"
|
||||
spending_proposal.valid?
|
||||
expect(spending_proposal.description).to eq("alert('danger');")
|
||||
end
|
||||
|
||||
it "should not be valid when very long" do
|
||||
spending_proposal.description = "a" * 6001
|
||||
expect(spending_proposal).to_not be_valid
|
||||
end
|
||||
end
|
||||
|
||||
describe "resolution status" do
|
||||
it "should be valid" do
|
||||
spending_proposal.resolution = "accepted"
|
||||
expect(spending_proposal).to be_valid
|
||||
spending_proposal.resolution = "rejected"
|
||||
expect(spending_proposal).to be_valid
|
||||
spending_proposal.resolution = "wrong"
|
||||
expect(spending_proposal).to_not be_valid
|
||||
end
|
||||
|
||||
it "can be accepted" do
|
||||
spending_proposal.accept
|
||||
expect(spending_proposal.reload.resolution).to eq("accepted")
|
||||
end
|
||||
|
||||
it "can be rejected" do
|
||||
spending_proposal.reject
|
||||
expect(spending_proposal.reload.resolution).to eq("rejected")
|
||||
end
|
||||
|
||||
describe "#accepted?" do
|
||||
it "should be true if resolution equals 'accepted'" do
|
||||
spending_proposal.resolution = "accepted"
|
||||
expect(spending_proposal.accepted?).to eq true
|
||||
end
|
||||
|
||||
it "should be false otherwise" do
|
||||
spending_proposal.resolution = "rejected"
|
||||
expect(spending_proposal.accepted?).to eq false
|
||||
spending_proposal.resolution = nil
|
||||
expect(spending_proposal.accepted?).to eq false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#rejected?" do
|
||||
it "should be true if resolution equals 'rejected'" do
|
||||
spending_proposal.resolution = "rejected"
|
||||
expect(spending_proposal.rejected?).to eq true
|
||||
end
|
||||
|
||||
it "should be false otherwise" do
|
||||
spending_proposal.resolution = "accepted"
|
||||
expect(spending_proposal.rejected?).to eq false
|
||||
spending_proposal.resolution = nil
|
||||
expect(spending_proposal.rejected?).to eq false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#unresolved?" do
|
||||
it "should be true if resolution is blank" do
|
||||
spending_proposal.resolution = nil
|
||||
expect(spending_proposal.unresolved?).to eq true
|
||||
end
|
||||
|
||||
it "should be false otherwise" do
|
||||
spending_proposal.resolution = "accepted"
|
||||
expect(spending_proposal.unresolved?).to eq false
|
||||
spending_proposal.resolution = "rejected"
|
||||
expect(spending_proposal.unresolved?).to eq false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "scopes" do
|
||||
before(:each) do
|
||||
2.times { create(:spending_proposal, resolution: "accepted") }
|
||||
2.times { create(:spending_proposal, resolution: "rejected") }
|
||||
2.times { create(:spending_proposal, resolution: nil) }
|
||||
end
|
||||
|
||||
describe "unresolved" do
|
||||
it "should return all spending proposals without resolution" do
|
||||
unresolved = SpendingProposal.all.unresolved
|
||||
expect(unresolved.size).to eq(2)
|
||||
unresolved.each {|u| expect(u.resolution).to be_nil}
|
||||
end
|
||||
end
|
||||
|
||||
describe "accepted" do
|
||||
it "should return all accepted spending proposals" do
|
||||
accepted = SpendingProposal.all.accepted
|
||||
expect(accepted.size).to eq(2)
|
||||
accepted.each {|a| expect(a.resolution).to eq("accepted")}
|
||||
end
|
||||
end
|
||||
|
||||
describe "rejected" do
|
||||
it "should return all rejected spending proposals" do
|
||||
rejected = SpendingProposal.all.rejected
|
||||
expect(rejected.size).to eq(2)
|
||||
rejected.each {|r| expect(r.resolution).to eq("rejected")}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user