diff --git a/.ruby-version b/.ruby-version index 585940699..a6254504e 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.2.3 +2.3.1 \ No newline at end of file diff --git a/Capfile b/Capfile index 372653a5e..0f53b8e9a 100644 --- a/Capfile +++ b/Capfile @@ -9,7 +9,7 @@ require 'capistrano/bundler' require 'capistrano/rails/assets' require 'capistrano/rails/migrations' #require 'capistrano/passenger' -require 'capistrano/delayed-job' +require 'capistrano/delayed_job' require 'whenever/capistrano' # Load custom tasks from `lib/capistrano/tasks` if you have any defined diff --git a/Gemfile b/Gemfile index 50b9e37e9..2ea2eb5c4 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ source 'https://rubygems.org' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '4.2.6' +gem 'rails', '4.2.7' # Use PostgreSQL gem 'pg' # Use SCSS for stylesheets @@ -9,7 +9,7 @@ gem 'sass-rails', '~> 5.0', '>= 5.0.4' # Use Uglifier as compressor for JavaScript assets gem 'uglifier', '>= 1.3.0' # Use CoffeeScript for .coffee assets and views -gem 'coffee-rails', '~> 4.1.0' +gem 'coffee-rails', '~> 4.2.1' # See https://github.com/rails/execjs#readme for more supported runtimes # gem 'therubyracer', platforms: :ruby @@ -34,21 +34,21 @@ gem 'responders' gem 'foundation-rails' gem 'foundation_rails_helper' gem 'acts_as_votable' -gem 'ckeditor', '~> 4.1.5' -gem 'invisible_captcha', '~> 0.8.2' +gem 'ckeditor', '~> 4.2.0' +gem 'invisible_captcha', '~> 0.9.1' gem 'cancancan' -gem 'social-share-button', git: 'https://github.com/huacnlee/social-share-button.git', ref: 'e46a6a3e82b86023bc' +gem 'social-share-button' gem 'initialjs-rails', '0.2.0.1' gem 'unicorn', '~> 5.1.0' gem 'paranoia' gem 'rinku', require: 'rails_rinku' gem 'savon' gem 'dalli' -gem 'rollbar', '~> 2.11.0' +gem 'rollbar', '~> 2.12.0' gem 'delayed_job_active_record', '~> 4.1.0' gem 'daemons' gem 'devise-async' -gem 'newrelic_rpm', '~> 3.14' +gem 'newrelic_rpm', '~> 3.16' gem 'whenever', require: false gem 'pg_search' @@ -66,7 +66,7 @@ group :development, :test do # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' gem 'spring-commands-rspec' - gem 'rspec-rails', '~> 3.3' + gem 'rspec-rails', '~> 3.5' gem 'capybara' gem 'factory_girl_rails' gem 'fuubar' @@ -74,9 +74,9 @@ group :development, :test do gem 'quiet_assets' gem 'letter_opener_web', '~> 1.3.0' gem 'i18n-tasks' - gem 'capistrano', '3.4.1', require: false + gem 'capistrano', '3.5.0', require: false gem "capistrano-bundler", '1.1.4', require: false - gem "capistrano-rails", '1.1.6', require: false + gem "capistrano-rails", '1.1.7', require: false gem "capistrano-rvm", require: false gem 'capistrano3-delayed-job', '~> 1.0' gem "bullet" @@ -92,5 +92,5 @@ end group :development do # Access an IRB console on exception pages or by using <%= console %> in views - gem 'web-console', '~> 3.0' + gem 'web-console', '3.3.0' end diff --git a/Gemfile.lock b/Gemfile.lock index 450d0f27b..ad24ae9ec 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,45 +1,36 @@ -GIT - remote: https://github.com/huacnlee/social-share-button.git - revision: e46a6a3e82b86023bc43b72c9379d3c6afe36b6b - ref: e46a6a3e82b86023bc - specs: - social-share-button (0.1.9) - coffee-rails - sass-rails - GEM remote: https://rubygems.org/ specs: - actionmailer (4.2.6) - actionpack (= 4.2.6) - actionview (= 4.2.6) - activejob (= 4.2.6) + actionmailer (4.2.7) + actionpack (= 4.2.7) + actionview (= 4.2.7) + activejob (= 4.2.7) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.6) - actionview (= 4.2.6) - activesupport (= 4.2.6) + actionpack (4.2.7) + actionview (= 4.2.7) + activesupport (= 4.2.7) rack (~> 1.6) rack-test (~> 0.6.2) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.6) - activesupport (= 4.2.6) + actionview (4.2.7) + activesupport (= 4.2.7) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - activejob (4.2.6) - activesupport (= 4.2.6) + activejob (4.2.7) + activesupport (= 4.2.7) globalid (>= 0.3.0) - activemodel (4.2.6) - activesupport (= 4.2.6) + activemodel (4.2.7) + activesupport (= 4.2.7) builder (~> 3.1) - activerecord (4.2.6) - activemodel (= 4.2.6) - activesupport (= 4.2.6) + activerecord (4.2.7) + activemodel (= 4.2.7) + activesupport (= 4.2.7) arel (~> 6.0) - activesupport (4.2.6) + activesupport (4.2.7) i18n (~> 0.7) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) @@ -49,7 +40,7 @@ GEM activerecord (>= 3.2, < 5) acts_as_votable (0.10.0) addressable (2.4.0) - ahoy_matey (1.4.0) + ahoy_matey (1.4.2) addressable browser (~> 2.0) geocoder @@ -57,9 +48,11 @@ GEM railties referer-parser (>= 0.3.0) request_store - safely_block + safely_block (>= 0.1.1) user_agent_parser uuidtools + airbrussh (1.0.2) + sshkit (>= 1.6.1, != 1.7.0) akami (1.3.1) gyoku (>= 0.4.0) nokogiri @@ -72,21 +65,24 @@ GEM babel-source (>= 4.0, < 6) execjs (~> 2.0) bcrypt (3.1.11) - browser (2.1.0) + browser (2.2.0) builder (3.2.2) - bullet (5.0.0) + bullet (5.1.1) activesupport (>= 3.0.0) - uniform_notifier (~> 1.9.0) - byebug (9.0.4) - cancancan (1.14.0) - capistrano (3.4.1) + uniform_notifier (~> 1.10.0) + byebug (9.0.5) + cancancan (1.15.0) + capistrano (3.5.0) + airbrussh (>= 1.0.0) + capistrano-harrow i18n rake (>= 10.0.0) - sshkit (~> 1.3) + sshkit (>= 1.9.0) capistrano-bundler (1.1.4) capistrano (~> 3.1) sshkit (~> 1.2) - capistrano-rails (1.1.6) + capistrano-harrow (0.5.2) + capistrano-rails (1.1.7) capistrano (~> 3.1) capistrano-bundler (~> 1.1) capistrano-rvm (0.1.2) @@ -102,7 +98,7 @@ GEM rack-test (>= 0.5.4) xpath (~> 2.0) chronic (0.10.2) - ckeditor (4.1.6) + ckeditor (4.2.0) cocaine orm_adapter (~> 0.5.0) climate_control (0.0.3) @@ -110,17 +106,17 @@ GEM cliver (0.3.2) cocaine (0.5.8) climate_control (>= 0.0.3, < 1.0) - coffee-rails (4.1.1) + coffee-rails (4.2.1) coffee-script (>= 2.2.0) - railties (>= 4.0.0, < 5.1.x) + railties (>= 4.0.0, < 5.2.x) coffee-script (2.4.1) coffee-script-source execjs coffee-script-source (1.10.0) concurrent-ruby (1.0.2) - coveralls (0.8.13) - json (~> 1.8) - simplecov (~> 0.11.0) + coveralls (0.8.14) + json (>= 1.8, < 3) + simplecov (~> 0.12.0) term-ansicolor (~> 1.3) thor (~> 0.19.1) tins (~> 1.6.0) @@ -133,15 +129,15 @@ GEM delayed_job_active_record (4.1.1) activerecord (>= 3.0, < 5.1) delayed_job (>= 3.0, < 5) - devise (3.5.7) + devise (3.5.10) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 3.2.6, < 5) responders thread_safe (~> 0.1) warden (~> 1.2.3) - devise-async (0.10.1) - devise (~> 3.2) + devise-async (0.10.2) + devise (>= 3.2, < 4.0) diff-lcs (1.2.5) docile (1.1.5) easy_translate (0.5.0) @@ -154,33 +150,33 @@ GEM mail (~> 2.6.3) errbase (0.0.3) erubis (2.7.0) - execjs (2.6.0) + execjs (2.7.0) factory_girl (4.7.0) activesupport (>= 3.0.0) factory_girl_rails (4.7.0) factory_girl (~> 4.7.0) railties (>= 3.0.0) - faker (1.6.3) + faker (1.6.5) i18n (~> 0.5) faraday (0.9.2) multipart-post (>= 1.2, < 3) - foundation-rails (6.2.1.0) + foundation-rails (6.2.3.0) railties (>= 3.1.0) sass (>= 3.3.0, < 3.5) sprockets-es6 (>= 0.9.0) - foundation_rails_helper (1.1.0) - actionpack (~> 4.1) - activemodel (~> 4.1) - activesupport (~> 4.1) - railties (~> 4.1) + foundation_rails_helper (1.2.1) + actionpack (>= 4.1) + activemodel (>= 4.1) + activesupport (>= 4.1) + railties (>= 4.1) tzinfo (~> 1.2, >= 1.2.2) - fuubar (2.0.0) + fuubar (2.1.1) rspec (~> 3.0) ruby-progressbar (~> 1.4) - geocoder (1.3.4) + geocoder (1.3.7) globalid (0.3.6) activesupport (>= 4.1.0) - groupdate (2.5.3) + groupdate (3.0.1) activesupport (>= 3) gyoku (1.3.1) builder (>= 2.1.2) @@ -202,7 +198,7 @@ GEM terminal-table (>= 1.5.1) initialjs-rails (0.2.0.1) railties (>= 3.1, < 5.0) - invisible_captcha (0.8.2) + invisible_captcha (0.9.1) rails jquery-rails (4.1.1) rails-dom-testing (>= 1, < 3) @@ -212,7 +208,7 @@ GEM railties (>= 3.2.16) json (1.8.3) jwt (1.5.4) - kaminari (0.16.3) + kaminari (0.17.0) actionpack (>= 3.0.0) activesupport (>= 3.0.0) kgio (2.10.0) @@ -228,20 +224,21 @@ GEM nokogiri (>= 1.5.9) mail (2.6.4) mime-types (>= 1.16, < 4) - mime-types (3.0) + mime-types (3.1) mime-types-data (~> 3.2015) - mime-types-data (3.2016.0221) - mini_portile2 (2.0.0) + mime-types-data (3.2016.0521) + mini_portile2 (2.1.0) minitest (5.9.0) multi_json (1.12.1) multi_xml (0.5.5) multipart-post (2.0.0) net-scp (1.2.1) net-ssh (>= 2.6.5) - net-ssh (3.1.1) - newrelic_rpm (3.15.2.317) - nokogiri (1.6.7.2) - mini_portile2 (~> 2.0.0.rc2) + net-ssh (3.2.0) + newrelic_rpm (3.16.0.318) + nokogiri (1.6.8) + mini_portile2 (~> 2.1.0) + pkg-config (~> 1.1.7) nori (2.6.0) oauth (0.5.0) oauth2 (1.0.0) @@ -275,14 +272,14 @@ GEM parser (2.3.0.6) ast (~> 2.2) pg (0.18.4) - pg_search (1.0.5) + pg_search (1.0.6) activerecord (>= 3.1) activesupport (>= 3.1) arel - poltergeist (1.9.0) + pkg-config (1.1.7) + poltergeist (1.10.0) capybara (~> 2.1) cliver (~> 0.3.1) - multi_json (~> 1.0) websocket-driver (>= 0.2.0) quiet_assets (1.1.0) railties (>= 3.1, < 5.0) @@ -293,16 +290,16 @@ GEM rack rack-test (0.6.3) rack (>= 1.0) - rails (4.2.6) - actionmailer (= 4.2.6) - actionpack (= 4.2.6) - actionview (= 4.2.6) - activejob (= 4.2.6) - activemodel (= 4.2.6) - activerecord (= 4.2.6) - activesupport (= 4.2.6) + rails (4.2.7) + actionmailer (= 4.2.7) + actionpack (= 4.2.7) + actionview (= 4.2.7) + activejob (= 4.2.7) + activemodel (= 4.2.7) + activerecord (= 4.2.7) + activesupport (= 4.2.7) bundler (>= 1.3.0, < 2.0) - railties (= 4.2.6) + railties (= 4.2.7) sprockets-rails rails-deprecated_sanitizer (1.0.3) activesupport (>= 4.2.0.alpha) @@ -312,49 +309,49 @@ GEM rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.3) loofah (~> 2.0) - railties (4.2.6) - actionpack (= 4.2.6) - activesupport (= 4.2.6) + railties (4.2.7) + actionpack (= 4.2.7) + activesupport (= 4.2.7) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) raindrops (0.16.0) - rake (11.1.2) + rake (11.2.2) redcarpet (3.3.4) referer-parser (0.3.0) request_store (1.3.1) responders (2.2.0) railties (>= 4.2.0, < 5.1) rinku (2.0.0) - rollbar (2.11.3) + rollbar (2.12.0) multi_json - rspec (3.4.0) - rspec-core (~> 3.4.0) - rspec-expectations (~> 3.4.0) - rspec-mocks (~> 3.4.0) - rspec-core (3.4.4) - rspec-support (~> 3.4.0) - rspec-expectations (3.4.0) + rspec (3.5.0) + rspec-core (~> 3.5.0) + rspec-expectations (~> 3.5.0) + rspec-mocks (~> 3.5.0) + rspec-core (3.5.1) + rspec-support (~> 3.5.0) + rspec-expectations (3.5.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.4.0) - rspec-mocks (3.4.1) + rspec-support (~> 3.5.0) + rspec-mocks (3.5.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.4.0) - rspec-rails (3.4.2) - actionpack (>= 3.0, < 4.3) - activesupport (>= 3.0, < 4.3) - railties (>= 3.0, < 4.3) - rspec-core (~> 3.4.0) - rspec-expectations (~> 3.4.0) - rspec-mocks (~> 3.4.0) - rspec-support (~> 3.4.0) - rspec-support (3.4.1) - ruby-progressbar (1.7.5) + rspec-support (~> 3.5.0) + rspec-rails (3.5.1) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.5.0) + rspec-expectations (~> 3.5.0) + rspec-mocks (~> 3.5.0) + rspec-support (~> 3.5.0) + rspec-support (3.5.0) + ruby-progressbar (1.8.1) safe_yaml (1.0.4) - safely_block (0.1.0) + safely_block (0.1.1) errbase sass (3.4.22) - sass-rails (5.0.4) - railties (>= 4.0.0, < 5.0) + sass-rails (5.0.5) + railties (>= 4.0.0, < 6) sass (~> 3.1) sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) @@ -367,26 +364,29 @@ GEM nokogiri (>= 1.4.0) nori (~> 2.4) wasabi (~> 3.4) - simplecov (0.11.2) + simplecov (0.12.0) docile (~> 1.1.0) - json (~> 1.8) + json (>= 1.8, < 3) simplecov-html (~> 0.10.0) simplecov-html (0.10.0) - spring (1.7.1) + social-share-button (0.3.1) + coffee-rails + sass-rails + spring (1.7.2) spring-commands-rspec (1.0.4) spring (>= 0.9.1) - sprockets (3.6.0) + sprockets (3.6.3) concurrent-ruby (~> 1.0) rack (> 1, < 3) sprockets-es6 (0.9.0) babel-source (>= 5.8.11) babel-transpiler sprockets (>= 3.0.0) - sprockets-rails (3.0.4) + sprockets-rails (3.1.1) actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) - sshkit (1.10.0) + sshkit (1.11.1) net-scp (>= 1.1.2) net-ssh (>= 2.8.0) term-ansicolor (1.3.2) @@ -395,7 +395,7 @@ GEM thor (0.19.1) thread (0.2.2) thread_safe (0.3.5) - tilt (2.0.4) + tilt (2.0.5) tins (1.6.0) tolk (1.9.3) rails (>= 4.0, < 4.3) @@ -413,7 +413,7 @@ GEM unicorn (5.1.0) kgio (~> 2.6) raindrops (~> 0.7) - uniform_notifier (1.9.0) + uniform_notifier (1.10.0) user_agent_parser (2.3.0) uuidtools (2.1.5) warden (1.2.6) @@ -421,14 +421,14 @@ GEM wasabi (3.5.0) httpi (~> 2.0) nokogiri (>= 1.4.2) - web-console (3.1.1) + web-console (3.3.0) activemodel (>= 4.2) debug_inspector railties (>= 4.2) - websocket-driver (0.6.3) + websocket-driver (0.6.4) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.2) - whenever (0.9.4) + whenever (0.9.7) chronic (>= 0.6.3) xpath (2.0.0) nokogiri (~> 1.3) @@ -445,14 +445,14 @@ DEPENDENCIES bullet byebug cancancan - capistrano (= 3.4.1) + capistrano (= 3.5.0) capistrano-bundler (= 1.1.4) - capistrano-rails (= 1.1.6) + capistrano-rails (= 1.1.7) capistrano-rvm capistrano3-delayed-job (~> 1.0) capybara - ckeditor (~> 4.1.5) - coffee-rails (~> 4.1.0) + ckeditor (~> 4.2.0) + coffee-rails (~> 4.2.1) coveralls daemons dalli @@ -469,13 +469,13 @@ DEPENDENCIES groupdate i18n-tasks initialjs-rails (= 0.2.0.1) - invisible_captcha (~> 0.8.2) + invisible_captcha (~> 0.9.1) jquery-rails jquery-ui-rails kaminari launchy letter_opener_web (~> 1.3.0) - newrelic_rpm (~> 3.14) + newrelic_rpm (~> 3.16) omniauth omniauth-facebook (~> 3.0.0) omniauth-google-oauth2 (~> 0.4.0) @@ -485,15 +485,15 @@ DEPENDENCIES pg_search poltergeist quiet_assets - rails (= 4.2.6) + rails (= 4.2.7) redcarpet responders rinku - rollbar (~> 2.11.0) - rspec-rails (~> 3.3) + rollbar (~> 2.12.0) + rspec-rails (~> 3.5) sass-rails (~> 5.0, >= 5.0.4) savon - social-share-button! + social-share-button spring spring-commands-rspec tolk @@ -501,8 +501,8 @@ DEPENDENCIES turnout uglifier (>= 1.3.0) unicorn (~> 5.1.0) - web-console (~> 3.0) + web-console (= 3.3.0) whenever BUNDLED WITH - 1.12.4 + 1.12.5 diff --git a/README.md b/README.md index 0ee254d3a..7a92401f3 100644 --- a/README.md +++ b/README.md @@ -8,17 +8,13 @@ Citizen Participation and Open Government Application [![Build Status](https://travis-ci.org/consul/consul.svg?branch=master)](https://travis-ci.org/consul/consul) [![Code Climate](https://codeclimate.com/github/consul/consul/badges/gpa.svg)](https://codeclimate.com/github/consul/consul) [![Dependency Status](https://gemnasium.com/consul/consul.svg)](https://gemnasium.com/consul/consul) -[![Coverage Status](https://coveralls.io/repos/consul/consul/badge.svg?branch=master&service=github)](https://coveralls.io/github/consul/consul?branch=master) +[![Coverage Status](https://coveralls.io/repos/github/consul/consul/badge.svg?branch=master)](https://coveralls.io/github/consul/consul?branch=master) This is the opensource code repository of the eParticipation website originally developed for the Madrid City government eParticipation website ## Current state -Development started on [2015 July 15th](https://github.com/consul/consul/commit/8db36308379accd44b5de4f680a54c41a0cc6fc6). Code was deployed to production on 2015 september 7th to [decide.madrid.es](https://decide.madrid.es). Since then new features are added often. You can take a look at a roadmap and future features in the [open issues list](https://github.com/consul/consul/issues). - -## Roadmap - -See [ROADMAP_ES.md](ROADMAP_ES.md) +Development started on [2015 July 15th](https://github.com/consul/consul/commit/8db36308379accd44b5de4f680a54c41a0cc6fc6). Code was deployed to production on 2015 september 7th to [decide.madrid.es](https://decide.madrid.es). Since then new features are added often. You can take a look at the current features in the [docs](https://github.com/consul/consul/tree/master/doc) and future features in the [open issues list](https://github.com/consul/consul/issues). ## Tech stack @@ -39,7 +35,7 @@ cp config/secrets.yml.example config/secrets.yml rake db:create bin/rake db:setup bin/rake db:dev_seed -RAILS_ENV=test bin/rake db:setup +RAILS_ENV=test rake db:setup ``` Run the app locally: @@ -58,12 +54,12 @@ bin/rspec You can use the default admin user from the seeds file: - **user:** admin@madrid.es + **user:** admin@consul.dev **pass:** 12345678 But for some actions like voting, you will need a verified user, the seeds file also includes one: - **user:** verified@madrid.es + **user:** verified@consul.dev **pass:** 12345678 ### OAuth diff --git a/README_ES.md b/README_ES.md index 9ae368848..489412299 100644 --- a/README_ES.md +++ b/README_ES.md @@ -8,17 +8,13 @@ Aplicación de Participación Ciudadana y Gobierno Abierto [![Build Status](https://travis-ci.org/consul/consul.svg?branch=master)](https://travis-ci.org/consul/consul) [![Code Climate](https://codeclimate.com/github/consul/consul/badges/gpa.svg)](https://codeclimate.com/github/consul/consul) [![Dependency Status](https://gemnasium.com/consul/consul.svg)](https://gemnasium.com/consul/consul) -[![Coverage Status](https://coveralls.io/repos/consul/consul/badge.svg?branch=master&service=github)](https://coveralls.io/github/consul/consul?branch=master) +[![Coverage Status](https://coveralls.io/repos/github/consul/consul/badge.svg?branch=master)](https://coveralls.io/github/consul/consul?branch=master) Este es el repositorio de código abierto de la Aplicación de Participación Ciudadana Consul, creada originariamente por el Ayuntamiento de Madrid. ## Estado del proyecto -El desarrollo de esta aplicación comenzó el [15 de Julio de 2015](https://github.com/consul/consul/commit/8db36308379accd44b5de4f680a54c41a0cc6fc6) y el código fue puesto en producción el día 7 de Septiembre de 2015 en [decide.madrid.es](https://decide.madrid.es). Desde entonces se le añaden mejoras y funcionalidades constantemente. La evolución y futura lista de funcionalidades a implementar se pueden consultar en la lista de [tareas por hacer](https://github.com/consul/consul/issues). - -## Hoja de ruta - -Ver fichero [ROADMAP_ES.md](ROADMAP_ES.md) +El desarrollo de esta aplicación comenzó el [15 de Julio de 2015](https://github.com/consul/consul/commit/8db36308379accd44b5de4f680a54c41a0cc6fc6) y el código fue puesto en producción el día 7 de Septiembre de 2015 en [decide.madrid.es](https://decide.madrid.es). Desde entonces se le añaden mejoras y funcionalidades constantemente. Las funcionalidades actuales se pueden consultar en la [documentación](https://github.com/consul/consul/tree/master/doc) y las siguientes funcionaliades en la lista de [tareas por hacer](https://github.com/consul/consul/issues). ## Tecnología @@ -39,7 +35,7 @@ cp config/secrets.yml.example config/secrets.yml rake db:create bin/rake db:setup bin/rake db:dev_seed -RAILS_ENV=test bin/rake db:setup +RAILS_ENV=test rake db:setup ``` Para ejecutar la aplicación en local: @@ -57,12 +53,12 @@ bin/rspec Puedes usar el usuario administrador por defecto del fichero seeds: - **user:** admin@madrid.es + **user:** admin@consul.dev **pass:** 12345678 Pero para ciertas acciones, como apoyar, necesitarás un usuario verificado, el fichero seeds proporciona uno: - **user:** verified@madrid.es + **user:** verified@consul.dev **pass:** 12345678 diff --git a/ROADMAP_ES.md b/ROADMAP_ES.md deleted file mode 100644 index 9e53b53c8..000000000 --- a/ROADMAP_ES.md +++ /dev/null @@ -1,26 +0,0 @@ -## Hoja de ruta - -Las necesidades y líneas de desarrollo de Consul a corto plazo se actualizan continuamente, y son añadidas como Issues https://github.com/consul/consul/issues La hoja de ruta de desarrollo a medio plazo comprende lo siguiente: - -## Debates y propuestas - -Entre las mejoras a desarrollar destacamos las siguientes: -- Búsquedas avanzadas -- Notificaciones de usuarios -- Listas de correo informativas para los usuarios -- Clasificaciones temáticas y locales -- Mejora del sistema de etiquetado -- Sistema de identificación de propuestas similares -- Mejora de algoritmos de ordenación -- Ampliación de licencias de contenidos -- Añadido de idiomas disponibles -- Universalización del código, y facilitación de adaptación a diferentes sistemas locales -- Creación de sección de procesos participativos ad-hoc - -## Presupuestos participativos - -Este espacio permitirá que una cierta cantidad de dinero se distribuya por decisión ciudadana. Para ello permitirá: recibir propuestas para este fin; que dichas propuestas sean tasadas y evaluadas por un cierto perfil de usuarios mostrando dicho trabajo junto a las mismas; mostrar las propuestas de tal forma que los usuarios verificados puedan votar un conjunto de ellas acorde con la cantidad de dinero reservada. El mecanismo contemplará mecanismos de pre-selección y selección, además de categorizaciones geográficas o temáticas de las propuestas. - -## Legislación colaborativa - -Este módulo permitirá la participación ciudadana en todas las fases de un desarrollo legislativo. Desde la propuesta y selección de los redactores y expertos de la legislación, pasando por la fase de debate y propuesta asociada a la misma (que a su vez se dividirá en espacios de debate libre y mecanismos de pregunta-respuesta), hasta la redacción colaborativa y la revisión detallada del texto creado. El módulo permitirá activar independientemente las diferentes fases del proceso, de tal forma que su uso pueda extenderse mucho más allá del caso de la redacción colaborativa. diff --git a/app/assets/images/banners/banner1.png b/app/assets/images/banners/banner1.png new file mode 100644 index 000000000..eff1cb9d7 Binary files /dev/null and b/app/assets/images/banners/banner1.png differ diff --git a/app/assets/images/banners/banner2.png b/app/assets/images/banners/banner2.png new file mode 100644 index 000000000..8ae0715e2 Binary files /dev/null and b/app/assets/images/banners/banner2.png differ diff --git a/app/assets/images/banners/banner3.png b/app/assets/images/banners/banner3.png new file mode 100644 index 000000000..e4ff49093 Binary files /dev/null and b/app/assets/images/banners/banner3.png differ diff --git a/app/assets/images/icon_mailer_comment.png b/app/assets/images/icon_mailer_comment.png new file mode 100644 index 000000000..d3c9bff73 Binary files /dev/null and b/app/assets/images/icon_mailer_comment.png differ diff --git a/app/assets/images/icon_mailer_reply.png b/app/assets/images/icon_mailer_reply.png new file mode 100644 index 000000000..0c9159e84 Binary files /dev/null and b/app/assets/images/icon_mailer_reply.png differ diff --git a/app/assets/images/icon_mailer_share.png b/app/assets/images/icon_mailer_share.png new file mode 100644 index 000000000..f95d44141 Binary files /dev/null and b/app/assets/images/icon_mailer_share.png differ diff --git a/app/assets/javascripts/advanced_search.js.coffee b/app/assets/javascripts/advanced_search.js.coffee index a5e657633..b38efb874 100644 --- a/app/assets/javascripts/advanced_search.js.coffee +++ b/app/assets/javascripts/advanced_search.js.coffee @@ -23,6 +23,8 @@ App.AdvancedSearch = $('.js-calendar').datepicker regional: locale maxDate: "+0d" + $('.js-calendar-full').datepicker + regional: locale initialize: -> App.AdvancedSearch.init_calendar() diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index e24d144bb..a1b8dd70a 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -44,6 +44,7 @@ //= require tracks //= require valuation_spending_proposal_form //= require embed_video +//= require banners var initialize_modules = function() { App.Comments.initialize(); @@ -63,6 +64,7 @@ var initialize_modules = function() { App.Tracks.initialize(); App.ValuationSpendingProposalForm.initialize(); App.EmbedVideo.initialize(); + App.Banners.initialize(); }; $(function(){ diff --git a/app/assets/javascripts/banners.js.coffee b/app/assets/javascripts/banners.js.coffee new file mode 100644 index 000000000..ec00abe95 --- /dev/null +++ b/app/assets/javascripts/banners.js.coffee @@ -0,0 +1,25 @@ +App.Banners = + + update_banner: (selector, text) -> + $(selector).html(text) + + update_style: (selector, style) -> + $(selector).removeClass($(selector).attr("class"), true) + .addClass(style, true) + + initialize: -> + $('[data-js-banner-title]').on + change: -> + App.Banners.update_banner("#js-banner-title", $(this).val()) + + $('[data-js-banner-description]').on + change: -> + App.Banners.update_banner("#js-banner-description", $(this).val()) + + $("#banner_style").on + change: -> + App.Banners.update_style("#js-banner-style", $(this).val()) + + $("#banner_image").on + change: -> + App.Banners.update_style("#js-banner-image", $(this).val()) diff --git a/app/assets/javascripts/votes.js.coffee b/app/assets/javascripts/votes.js.coffee index e4223c644..030b9cf46 100644 --- a/app/assets/javascripts/votes.js.coffee +++ b/app/assets/javascripts/votes.js.coffee @@ -1,20 +1,22 @@ App.Votes = hoverize: (votes) -> - $(votes).hover -> - $("div.anonymous-votes", votes).show(); - $("div.organizations-votes", votes).show(); - $("div.not-logged", votes).show(); - $("div.no-supports-allowed", votes).show(); - $("div.logged", votes).hide(); - , -> - $("div.anonymous-votes", votes).hide(); - $("div.organizations-votes", votes).hide(); - $("div.not-logged", votes).hide(); - $("div.no-supports-allowed", votes).hide(); - $("div.logged", votes).show(); + $(document).on { + 'mouseenter focus': -> + $("div.anonymous-votes", this).show(); + $("div.organizations-votes", this).show(); + $("div.not-logged", this).show(); + $("div.no-supports-allowed", this).show(); + $("div.logged", this).hide(); + mouseleave: -> + $("div.anonymous-votes", this).hide(); + $("div.organizations-votes", this).hide(); + $("div.not-logged", this).hide(); + $("div.no-supports-allowed", this).hide(); + $("div.logged", this).show(); + }, votes initialize: -> - App.Votes.hoverize votes for votes in $("div.votes") - App.Votes.hoverize votes for votes in $("div.supports") + App.Votes.hoverize "div.votes" + App.Votes.hoverize "div.supports" false diff --git a/app/assets/stylesheets/_settings.scss b/app/assets/stylesheets/_settings.scss index 22e7ac8de..44433938b 100644 --- a/app/assets/stylesheets/_settings.scss +++ b/app/assets/stylesheets/_settings.scss @@ -3,6 +3,7 @@ // // Table of Contents: // +// 0. Custom variables // 1. Global // 2. Breakpoints // 3. The Grid @@ -43,6 +44,70 @@ @import 'util/util'; +// 0. Custom variables +// -------------------- + +$base-font-size: rem-calc(17); +$base-line-height: rem-calc(26); +$small-font-size: rem-calc(14); +$line-height: rem-calc(24); + +$brand: #004A83; +$body: #E9E9E9; +$background: #EDEFF0; +$border: #DEE0E3; +$dark: darken($brand, 10%); + +$text: #222222; +$text-medium: #999999; +$text-light: #CCCCCC; + +$link: #2895F1; +$link-hover: #2178BF; + +$debates: #008CCF; +$votes-bg: #26AEEE; +$votes-border: #1F94CB; + +$votes-like: #7BD2A8; +$votes-like-act: #5D9E7F; +$votes-unlike: #EF8585; +$votes-unlike-act: #BD6A6A; + +$delete: #F04124; +$check: #46DB91; + +$proposals: #FFA42D; +$proposals-border: #CC8425; + +$budget: #454372; +$budget-hover: #7571BF; + +$highlight: #E7F2FC; +$featured: #FED900; + +$footer-bg: #DEE0E2; +$footer-color: #171819; +$footer-link: #454A4C; +$footer-border: #BFC1C3; + +$success-bg: #DFF0D8; +$success-border: #D6E9C6; +$color-success: #3C763D; + +$info-bg: #D9EDF7; +$info-border: #BCE8F1; +$color-info: #31708F; + +$warning-bg: #FCF8E3; +$warning-border: #FAEBCC; +$color-warning: #8A6D3B; + +$alert-bg: #F2DEDE; +$alert-border: #EBCCD1; +$color-alert: #A94442; + + // 1. Global // --------- @@ -127,7 +192,7 @@ $header-color: inherit; $header-lineheight: 1.4; $header-margin-bottom: 0.5rem; $header-text-rendering: optimizeLegibility; -$small-font-size: 80%; +$small-font-size: rem-calc(14); $header-small-font-color: $medium-gray; $paragraph-lineheight: 1.6; $paragraph-margin-bottom: 1rem; @@ -194,12 +259,12 @@ $input-error-font-weight: $global-weight-bold; $accordion-background: $white; $accordion-plusminus: true; -$accordion-item-color: foreground($accordion-background, $primary-color); +$accordion-item-color: foreground($accordion-background, $text); $accordion-item-background-hover: $light-gray; $accordion-item-padding: 1.25rem 1rem; $accordion-content-background: $white; $accordion-content-border: 1px solid $light-gray; -$accordion-content-color: foreground($accordion-background, $primary-color); +$accordion-content-color: foreground($accordion-background, $text); $accordion-content-padding: 1rem; // 8. Accordion Menu @@ -510,13 +575,13 @@ $show-header-for-stacked: false; $tab-margin: 0; $tab-background: $white; -$tab-background-active: $light-gray; -$tab-item-font-size: rem-calc(12); +$tab-background-active: $white; +$tab-item-font-size: $base-font-size; $tab-item-background-hover: $white; -$tab-item-padding: 1.25rem 1.5rem; +$tab-item-padding: $line-height/2 0; $tab-expand-max: 6; $tab-content-background: $white; -$tab-content-border: $light-gray; +$tab-content-border: $border; $tab-content-color: foreground($tab-background, $primary-color); $tab-content-padding: 1rem; @@ -563,66 +628,3 @@ $topbar-submenu-background: $topbar-background; $topbar-title-spacing: 1rem; $topbar-input-width: 200px; $topbar-unstack-breakpoint: medium; - -// 37. Custom variables -// -------------------- - -$base-font-size: rem-calc(17); -$base-line-height: rem-calc(26); -$small-font-size: rem-calc(14); -$line-height: rem-calc(24); - -$brand: #004A83; -$body: #E9E9E9; -$background: #EDEFF0; -$border: #DEE0E3; -$dark: darken($brand, 10%); - -$text: #222222; -$text-medium: #999999; -$text-light: #CCCCCC; - -$link: #2895F1; -$link-hover: #2178BF; - -$debates: #008CCF; -$votes-bg: #26AEEE; -$votes-border: #1F94CB; - -$votes-like: #7BD2A8; -$votes-like-act: #5D9E7F; -$votes-unlike: #EF8585; -$votes-unlike-act: #BD6A6A; - -$delete: #F04124; -$check: #46DB91; - -$proposals: #FFA42D; -$proposals-border: #CC8425; - -$budget: #454372; -$budget-hover: #7571BF; - -$highlight: #E7F2FC; -$featured: #FED900; - -$footer-bg: #DEE0E2; -$footer-color: #171819; -$footer-link: #454A4C; -$footer-border: #BFC1C3; - -$success-bg: #DFF0D8; -$success-border: #D6E9C6; -$color-success: #3C763D; - -$info-bg: #D9EDF7; -$info-border: #BCE8F1; -$color-info: #31708F; - -$warning-bg: #FCF8E3; -$warning-border: #FAEBCC; -$color-warning: #8A6D3B; - -$alert-bg: #F2DEDE; -$alert-border: #EBCCD1; -$color-alert: #A94442; diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index 48642841d..cd8241fca 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -8,67 +8,72 @@ // // 01. Global styles -// - - - - - - - - - - - - - - - - - - - - - - - - - +// ----------------- + +$admin-color: #CF3638; body.admin { + header { + border: 0; + + .top-links { + background: darken($admin-color, 15%); + } + } + + .top-bar { + background: $admin-color !important; + height: auto; + } + form { + .button { margin-top: 0; } input[type="text"], textarea { - height: 48px\9; - line-height: 48px\9; - margin-bottom: 24px\9; width: 100%; } } table { + th { + text-align: left; + } + tr { - background: #f4f4f4; + background: white; + border: 1px solid $border; - &:nth-child(odd) { - background: white; - } - - &:nth-child(even) { - background: #f0f0f0; + &:hover { + background: #f3f6f7; } } - td.small { - font-size: $small-font-size; + input[type="submit"] ~ a, a ~ a { + margin-left: $line-height/2; + margin-right: $line-height/2; } } + hr { + max-width: none; + } + + .menu.simple li.active { + border-bottom: 2px solid $admin-color; + color: $admin-color; + } + #proposals { width: 100% !important; } - .dashboard { - margin-bottom: rem-calc(48); - - ul, ol { - margin-left: rem-calc(12); - - li { - font-size: rem-calc(15); - line-height: rem-calc(30); - margin-bottom: rem-calc(12); - } - } - - p { - font-size: rem-calc(15); - line-height: rem-calc(30); - } - - h3 { - font-weight: bold; - } + .accordion-title { + font-size: $base-font-size; } .button.secondary { @@ -99,17 +104,54 @@ body.admin { display: none; } +.admin-content { + padding: $line-height !important; +} + +@include breakpoint(medium) { + + tr { + + .on-hover-block { + display: none; + } + + &:hover .on-hover-block { + display: block; + margin: 0; + margin-top: $line-height/2; + width: 100%; + } + } +} + +@include breakpoint(medium) { + + tr { + + .on-hover { + display: none; + } + + &:hover .on-hover { + display: inline; + } + } +} + // 02. Sidebar -// - - - - - - - - - - - - - - - - - - - - - - - - - +// ----------- .admin-sidebar { + border-right: 1px solid $border; - a { - color: white\9 !important; + @include breakpoint(medium) { + padding-bottom: $line-height*3; } ul { list-style-type: none; + margin-bottom: 0; margin-left: 0; padding: 0; @@ -118,85 +160,44 @@ body.admin { font-size: rem-calc(24); padding-right: rem-calc(12); padding-top: rem-calc(4); - padding-left: 12px\9 !important; - padding-right: 12px\9 !important; + vertical-align: middle; } li { - background: #2E343F; - border-bottom: 1px solid #292f39; - border-top: 1px solid #353c49; + background: white; margin: 0; outline: 0; - &:first-child { + &.active a { + background: #f3f6f7; + color: $admin-color; font-weight: bold; - text-transform: uppercase; - } - - &.active{ - background: #373D47; - - a:not(.button) { - color: white; - } } } - li a:not(.button) { - color: rgba(255,255,255,0.3); + li.section { + border-bottom: 1px dotted #d5d5d5; + border-top: 1px dotted #d5d5d5; + height: $line-height/2; + } + + li a { + color: $text; + display: block; line-height: rem-calc(48); padding-left: rem-calc(12); vertical-align: top; &:hover { - color: white; + background: #f3f6f7; + text-decoration: none; } } } } // 03. List elements -// - - - - - - - - - - - - - - - - - - - - - - - - - - -.admin-list { - list-style-type: none; - margin: 0; - margin-bottom: rem-calc(48); - - form { - clear: both; - - .checkbox { - font-size: $small-font-size; - } - } - - li { - border-bottom: 1px solid #E7E9EC; - font-size: rem-calc(14); - min-height: rem-calc(72); - padding: rem-calc(12); - - &:first-child { - border-top: 1px solid #E7E9EC; - } - - &:nth-child(odd) { - background: #F0F2F6; - } - } - - .tag { - float: left; - font-size: rem-calc(18); - padding: 0; - } - - .button { - margin: 0; - } -} +// ----------------- .delete { border-bottom: 1px dotted #CF2A0E; @@ -239,14 +240,9 @@ body.admin { font-style: italic; } -.level { - font-size: rem-calc(12); -} - .official { background-color: #e7e7e7; border-radius: rem-calc(3); - font-size: rem-calc(12); font-weight: normal; padding: rem-calc(6) rem-calc(12); } @@ -262,13 +258,10 @@ body.admin { .moderation-description { max-height: rem-calc(65); overflow: hidden; - max-width: rem-calc(590); + max-width: rem-calc(700); &:hover { - cursor: text; max-height: rem-calc(1000); - outline: 3px solid #ffbf47; - padding: rem-calc(12); transition: max-height 0.9s; -moz-transition: max-height 0.9s; -webkit-transition: max-height 0.9s; @@ -276,7 +269,7 @@ body.admin { } // 04. Stats -// - - - - - - - - - - - - - - - - - - - - - - - - - +// --------- .stats { background: white; @@ -304,7 +297,7 @@ body.admin { } // 05. Management -// - - - - - - - - - - - - - - - - - - - - - - - - - +// -------------- .user-permissions { @@ -337,8 +330,8 @@ body.admin { border-radius: rem-calc(3); font-size: rem-calc(16); font-weight: normal; - margin-bottom: rem-calc(12); - padding: rem-calc(6) rem-calc(12); + margin: $line-height; + padding: $line-height/2; strong { font-size: rem-calc(18); diff --git a/app/assets/stylesheets/datepicker_overrides.scss b/app/assets/stylesheets/datepicker_overrides.scss index 88f17c7cc..dbbab4bd5 100644 --- a/app/assets/stylesheets/datepicker_overrides.scss +++ b/app/assets/stylesheets/datepicker_overrides.scss @@ -51,7 +51,7 @@ border-right: 1px solid $dark; tr th { - color: white; + color: $dark; } } diff --git a/app/assets/stylesheets/ie.scss b/app/assets/stylesheets/ie.scss new file mode 100644 index 000000000..2c494747b --- /dev/null +++ b/app/assets/stylesheets/ie.scss @@ -0,0 +1,199 @@ +// Stylesheet for Internet Explorer +// +// Table of Contents +// 01. Global styles +// 02. Admin +// + +// 01. Global styles +// ----------------- + +*, *:before, *:after { + box-sizing: border-box !important; +} + +.show-for-medium-down, +.show-for-medium, +.show-for-small { + display: none !important; +} + +.show-for-large-up, +.hide-for-medium-down { + display: block !important; +} + +.column, .columns { + display: inline-block !important; + float: none !important; + box-sizing: border-box !important; +} + +.small-1, .row .small-1 { width: 7.33333%; } +.small-2, .row .small-2 { width: 15.66667%; } +.small-3, .row .small-3 { width: 24%; } +.small-4, .row .small-4 { width: 32.33333%; } +.small-5, .row .small-5 { width: 40.66667%; } +.small-6, .row .small-6 { width: 49%; } +.small-7, .row .small-7 { width: 57.33333%; } +.small-8, .row .small-8 { width: 65.66667%; } +.small-9, .row .small-9 { width: 74%; } +.small-10, .row .small-10 { width: 82.33333%; } +.small-11, .row .small-11 { width: 90.66667%; } +.small-12, .row .small-12 { width: 99%; } + +.medium-1, .row .medium-1 { width: 7.33333%; } +.medium-2, .row .medium-2 { width: 15.66667%; } +.medium-3, .row .medium-3 { width: 24%; } +.medium-4, .row .medium-4 { width: 32.33333%; } +.medium-5, .row .medium-5 { width: 40.66667%; } +.medium-6, .row .medium-6 { width: 49%; } +.medium-7, .row .medium-7 { width: 57.33333%; } +.medium-8, .row .medium-8 { width: 65.66667%; } +.medium-9, .row .medium-9 { width: 74%; } +.medium-10, .row .medium-10 { width: 82.33333%; } +.medium-11, .row .medium-11 { width: 90.66667%; } +.medium-12, .row .medium-12 { width: 99%; } + +.large-1, .row .large-1 { width: 7.33333%; } +.large-2, .row .large-2 { width: 15.66667%; } +.large-3, .row .large-3 { width: 24%; } +.large-4, .row .large-4 { width: 32.33333%; } +.large-5, .row .large-5 { width: 40.66667%; } +.large-6, .row .large-6 { width: 49%; } +.large-7, .row .large-7 { width: 57.33333%; } +.large-8, .row .large-8 { width: 65.66667%; } +.large-9, .row .large-9 { width: 74%; } +.large-10, .row .large-10 { width: 82.33333%; } +.large-11, .row .large-11 { width: 90.66667%; } +.large-12, .row .large-12 { width: 99%; } + +.row .small-offset-1 { margin-left: 7.33333%; } +.row .small-offset-2 { margin-left: 15.66667%; } +.row .small-offset-3 { margin-left: 24%; } +.row .small-offset-4 { margin-left: 32.33333%; } +.row .small-offset-5 { margin-left: 40.66667%; } +.row .small-offset-6 { margin-left: 49%; } +.row .small-offset-7 { margin-left: 57.33333%; } +.row .small-offset-8 { margin-left: 65.66667%; } +.row .small-offset-9 { margin-left: 74%; } +.row .small-offset-10 { margin-left: 82.33333%; } +.row .small-offset-11 { margin-left: 90.66667%; } +.row .small-offset-12 { margin-left: 99%; } + +.row .medium-offset-1 { margin-left: 7.33333%; } +.row .medium-offset-2 { margin-left: 15.66667%; } +.row .medium-offset-3 { margin-left: 24%; } +.row .medium-offset-4 { margin-left: 32.33333%; } +.row .medium-offset-5 { margin-left: 40.66667%; } +.row .medium-offset-6 { margin-left: 49%; } +.row .medium-offset-7 { margin-left: 57.33333%; } +.row .medium-offset-8 { margin-left: 65.66667%; } +.row .medium-offset-9 { margin-left: 74%; } +.row .medium-offset-10 { margin-left: 82.33333%; } +.row .medium-offset-11 { margin-left: 90.66667%; } +.row .medium-offset-12 { margin-left: 99%; } + +.row .large-offset-1 { margin-left: 7.33333%; } +.row .large-offset-2 { margin-left: 15.66667%; } +.row .large-offset-3 { margin-left: 24%; } +.row .large-offset-4 { margin-left: 32.33333%; } +.row .large-offset-5 { margin-left: 40.66667%; } +.row .large-offset-6 { margin-left: 49%; } +.row .large-offset-7 { margin-left: 57.33333%; } +.row .large-offset-8 { margin-left: 65.66667%; } +.row .large-offset-9 { margin-left: 74%; } +.row .large-offset-10 { margin-left: 82.33333%; } +.row .large-offset-11 { margin-left: 90.66667%; } +.row .large-offset-12 { margin-left: 99%; } + +.top-bar { + clear: both !important; + height: 100px !important; +} + +.locale, .external-links { + background: #002d50 !important; +} + +.locale { + float: left !important; +} + +.external-links { + color: white !important; + float: right !important; +} + +.top-bar-title, .top-bar-title a, .top-bar-title a { + display: inline-block !important; + float: none !important; +} + +.top-bar-title a { + line-height: 24px !important; + width: 100% !important; +} + +.proposal .supports { + display: inline-block !important; + margin: 0 !important; + position: inherit !important; + + &:after { + content: none !important; + } +} + +form { + + input, textarea { + height: 48px !important; + line-height: 48px !important; + margin-bottom: 24px !important; + width: 100% !important; + } + + input[type="checkbox"], + input[type="radio"] { + height: auto !important; + line-height: inherit !important; + width: auto !important; + } + + input[type="radio"] { + width: 18px !important; + } +} + +.subnavigation { + display: block; + height: 60px !important; + width: 100%; + + ul li a { + margin-left: 10px !important; + margin-right: 10px !important; + } +} + +.truncate { + background: none; +} + +// 02. Admin +// --------- + +body.admin form { + + input[type="text"], textarea { + height: 48px !important; + line-height: 48px !important; + margin-bottom: 24px !important; + } +} + +.admin-sidebar ul [class^="icon-"] { + padding-left: 12px !important; + padding-right: 12px !important; +} diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss index c8f3624ea..215f2453d 100644 --- a/app/assets/stylesheets/layout.scss +++ b/app/assets/stylesheets/layout.scss @@ -17,6 +17,7 @@ // 15. Comments // 16. Flags // 17. Activity +// 18. Banners // // 01. Global styles @@ -218,9 +219,48 @@ a { float: left; } -.table-fixed { - table-layout: fixed; -} +//<<<<<<< HEAD +//.table-fixed { +// table-layout: fixed; +//======= +//.tabs-content { +// border: 0; +//} +// +//.tabs { +// border: { +// left: 0; +// right: 0; +// top: 0; +// }; +// margin-bottom: $line-height; +// +// .tabs-title > a { +// color: $text-medium; +// margin-bottom: rem-calc(-1); +// margin-right: $line-height; +// +// &[aria-selected='true'], +// &.is-active { +// color: $brand; +// border-bottom: 2px solid $brand; +// font-weight: bold; +// } +// } +// +// h2 { +// font-size: $base-font-size; +// } +//} +// +//.no-max-width { +// max-width: none; +//} +// +//.button.float-right ~ .button.float-right { +// margin: 0 $line-height/2; +//>>>>>>> budget +//} // 02. Header // ---------- @@ -361,8 +401,6 @@ header { color: $text; display: block; font-weight: bold; - margin-left: 18px\9; - margin-right: 18px\9; width: auto; &:hover { @@ -636,24 +674,9 @@ form { font-weight: bold; } - input, textarea { - height: 48px\9; - line-height: 48px\9; - margin-bottom: 24px\9; - width: 100%\9; - } - - input[type="checkbox"], - input[type="radio"] { - height: auto\9; - line-height: inherit\9; - width: auto\9; - } - input[type="radio"] { height: $line-height !important; vertical-align: top; - width: 18px\9; + label { font-weight: normal; @@ -1067,12 +1090,13 @@ table { } } -.social-share-button-twitter { +.ssb-twitter { background: #45B0E3; + background-image: none !important; color: white; - height: $line-height*2; + height: $line-height*2 !important; position: relative; - width: $line-height*2; + width: $line-height*2 !important; &:before { content: "f"; @@ -1106,12 +1130,13 @@ table { } } -.social-share-button-facebook { +.ssb-facebook { background: #3B5998; + background-image: none !important; color: white; - height: rem-calc(48); + height: rem-calc(48) !important; position: relative; - width: rem-calc(48); + width: rem-calc(48) !important; &:before { content: "A"; @@ -1145,12 +1170,13 @@ table { } } -.social-share-button-google_plus { +.ssb-google_plus { background: #DE4C34; + background-image: none !important; color: white; - height: $line-height*2; + height: $line-height*2 !important; position: relative; - width: $line-height*2; + width: $line-height*2 !important; &:before { content: "B"; @@ -1188,7 +1214,7 @@ table { display: inline-block; } - .social-share-button-twitter { + .ssb-twitter { background: none; color: white; height: $line-height; @@ -1211,7 +1237,7 @@ table { } } - .social-share-button-facebook { + .ssb-facebook { background: none; color: white; height: rem-calc(24); @@ -1234,7 +1260,7 @@ table { } } - .social-share-button-google_plus { + .ssb-google_plus { background: none; color: white; height: rem-calc(24); @@ -1463,7 +1489,6 @@ table { .comments { background: $white; background-repeat: repeat-x; - padding-top: $line-height; padding-bottom: $line-height*4; h2 { @@ -1487,7 +1512,7 @@ table { .comment-votes { color: $text-medium; - font-size: $small-font-size; + font-size: rem-calc(14); line-height: $line-height; a { @@ -1650,7 +1675,7 @@ table { &:first-child { padding-left: $line-height*1.5; - width: 80%; + width: 75%; } &:before { @@ -1690,3 +1715,69 @@ table { } } } + +// 18. Banners +// ----------- + +.banner-style-one { + background-color: $brand; +} + +.banner-style-two { + background-color: $budget; +} + +.banner-style-three { + background-color: #33DADF; +} + +@include breakpoint(large) { + + .banner-img-one { + background-image: image-url('banners/banner1.png'); + } + + .banner-img-two { + background-image: image-url('banners/banner2.png'); + } + + .banner-img-three { + background-image: image-url('banners/banner3.png'); + } +} + +.banner-img-one, .banner-img-two, .banner-img-three { + background-position: bottom right; + background-repeat: no-repeat; +} + +.banner-style-one, .banner-style-two, .banner-style-three { + margin: 0; + margin-bottom: $line-height; + + h2, h3, a { + color: #eaeaf2; + } + + h2 { + padding: $line-height/2; + padding-bottom: 0; + } + + h3 { + padding: $line-height/2; + padding-top: 0; + } + + a:hover h2, a:hover h3 { + color: #eaeaf2 !important; + text-decoration: none; + } + + @include breakpoint(large) { + + h3 { + width: 80%; + } + } +} diff --git a/app/assets/stylesheets/mixins.scss b/app/assets/stylesheets/mixins.scss index b1947768b..d772b8ace 100644 --- a/app/assets/stylesheets/mixins.scss +++ b/app/assets/stylesheets/mixins.scss @@ -8,6 +8,7 @@ @mixin logo { color: white; + display: inline-block; font-family: 'Lato' !important; font-size: rem-calc(24); font-weight: lighter; diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index c5a4bf3fd..e6a262d07 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -720,6 +720,16 @@ } } +.more-info { + clear: both; + color: $text-medium; + font-size: $small-font-size; + + a { + color: $text-medium; + } +} + .debate { .votes { @@ -897,9 +907,9 @@ .share-supported { - .social-share-button-twitter, - .social-share-button-facebook, - .social-share-button-google_plus { + .ssb-twitter, + .ssb-facebook, + .ssb-google_plus { color: $budget; } } @@ -1016,9 +1026,9 @@ .share-supported { - .social-share-button-twitter, - .social-share-button-facebook, - .social-share-button-google_plus { + .ssb-twitter, + .ssb-facebook, + .ssb-google_plus { height: rem-calc(33); &:before { diff --git a/app/assets/stylesheets/print.css b/app/assets/stylesheets/print.css index 29096ae13..de5a56a31 100644 --- a/app/assets/stylesheets/print.css +++ b/app/assets/stylesheets/print.css @@ -12,6 +12,8 @@ #print_link { display: none !important; } +#responsive-menu { display: none !important; } + .admin-sidebar { display: none !important; } img.left { display: none !important; } diff --git a/app/controllers/account_controller.rb b/app/controllers/account_controller.rb index 9a0f89bae..c3d814b38 100644 --- a/app/controllers/account_controller.rb +++ b/app/controllers/account_controller.rb @@ -25,7 +25,7 @@ class AccountController < ApplicationController if @account.organization? params.require(:account).permit(:phone_number, :email_on_comment, :email_on_comment_reply, :newsletter, organization_attributes: [:name, :responsible_name]) else - params.require(:account).permit(:username, :public_activity, :email_on_comment, :email_on_comment_reply, :newsletter) + params.require(:account).permit(:username, :public_activity, :email_on_comment, :email_on_comment_reply, :email_on_direct_message, :email_digest, :newsletter, :official_position_badge) end end diff --git a/app/controllers/admin/banners_controller.rb b/app/controllers/admin/banners_controller.rb new file mode 100644 index 000000000..dbf683b9a --- /dev/null +++ b/app/controllers/admin/banners_controller.rb @@ -0,0 +1,56 @@ +class Admin::BannersController < Admin::BaseController + + has_filters %w{all with_active with_inactive}, only: :index + + before_action :find_banner, only: [:edit, :update, :destroy] + before_action :banner_styles, only: [:edit, :new, :create, :update] + before_action :banner_imgs, only: [:edit, :new, :create, :update] + + respond_to :html, :js + + load_and_authorize_resource + + def index + @banners = Banner.send(@current_filter).page(params[:page]) + end + + def create + @banner = Banner.new(banner_params) + if @banner.save + redirect_to admin_banners_path + else + render :new + end + end + + def update + @banner.assign_attributes(banner_params) + if @banner.update(banner_params) + redirect_to admin_banners_path + else + render :edit + end + end + + def destroy + @banner.destroy + redirect_to admin_banners_path + end + + private + def banner_params + params.require(:banner).permit(:title, :description, :target_url, :style, :image, :post_started_at, :post_ended_at) + end + + def find_banner + @banner = Banner.find(params[:id]) + end + + def banner_styles + @banner_styles = Setting.all.banner_style.map { |banner_style| [banner_style.value, banner_style.key.split('.')[1]] } + end + + def banner_imgs + @banner_imgs = Setting.all.banner_img.map { |banner_img| [banner_img.value, banner_img.key.split('.')[1]] } + end +end \ No newline at end of file diff --git a/app/controllers/admin/settings_controller.rb b/app/controllers/admin/settings_controller.rb index 387f38177..17bd364f3 100644 --- a/app/controllers/admin/settings_controller.rb +++ b/app/controllers/admin/settings_controller.rb @@ -1,9 +1,11 @@ class Admin::SettingsController < Admin::BaseController def index - all_settings = (Setting.all).group_by { |s| s.feature_flag? } - @settings = all_settings[false] - @feature_flags = all_settings[true] + all_settings = (Setting.all).group_by { |s| s.type } + @settings = all_settings['common'] + @feature_flags = all_settings['feature'] + @banner_styles = all_settings['banner-style'] + @banner_imgs = all_settings['banner-img'] end def update diff --git a/app/controllers/admin/stats_controller.rb b/app/controllers/admin/stats_controller.rb index abfecdd7f..7e5b902e9 100644 --- a/app/controllers/admin/stats_controller.rb +++ b/app/controllers/admin/stats_controller.rb @@ -21,6 +21,15 @@ class Admin::StatsController < Admin::BaseController @user_ids_who_voted_proposals = ActsAsVotable::Vote.where(votable_type: 'Proposal').distinct.count(:voter_id) @user_ids_who_didnt_vote_proposals = @verified_users - @user_ids_who_voted_proposals @spending_proposals = SpendingProposal.count + end + def proposal_notifications + @proposal_notifications = ProposalNotification.all + @proposals_with_notifications = @proposal_notifications.select(:proposal_id).distinct.count + end + + def direct_messages + @direct_messages = DirectMessage.count + @users_who_have_sent_message = DirectMessage.select(:sender_id).distinct.count end end diff --git a/app/controllers/budget/budgets_controller.rb b/app/controllers/budget/budgets_controller.rb new file mode 100644 index 000000000..c084f4475 --- /dev/null +++ b/app/controllers/budget/budgets_controller.rb @@ -0,0 +1,10 @@ +class Budget + class BudgetsController < ApplicationController + load_and_authorize_resource + + def index + @budgets = Budget.all + end + + end +end \ No newline at end of file diff --git a/app/controllers/budget/investments_controller.rb b/app/controllers/budget/investments_controller.rb new file mode 100644 index 000000000..d08038174 --- /dev/null +++ b/app/controllers/budget/investments_controller.rb @@ -0,0 +1,85 @@ +class Budget + class InvestmentsController < ApplicationController + include FeatureFlags + + before_action :load_investments, only: [:index] + before_action :load_geozone, only: [:index, :unfeasible] + + skip_authorization_check + + before_action :authenticate_user!, except: [:index, :show] + before_action -> { flash.now[:notice] = flash[:notice].html_safe if flash[:html_safe] && flash[:notice] } + + load_and_authorize_resource + + feature_flag :spending_proposals + + invisible_captcha only: [:create, :update], honeypot: :subtitle + + respond_to :html, :js + + def index + load_investments + set_spending_proposal_votes(@investments) + end + + def new + @spending_proposal = SpendingProposal.new + end + + def show + set_spending_proposal_votes(@spending_proposal) + end + + def create + @spending_proposal = SpendingProposal.new(spending_proposal_params) + @spending_proposal.author = current_user + + if @spending_proposal.save + notice = t('flash.actions.create.spending_proposal', activity: "#{t('layouts.header.my_activity_link')}") + redirect_to @spending_proposal, notice: notice, flash: { html_safe: true } + else + render :new + end + end + + def destroy + spending_proposal = SpendingProposal.find(params[:id]) + spending_proposal.destroy + redirect_to user_path(current_user, filter: 'spending_proposals'), notice: t('flash.actions.destroy.spending_proposal') + end + + def vote + @spending_proposal.register_vote(current_user, 'yes') + set_spending_proposal_votes(@spending_proposal) + end + + private + + def spending_proposal_params + params.require(:spending_proposal).permit(:title, :description, :external_url, :geozone_id, :association_name, :terms_of_service) + end + + def load_investments + @investments = filter_and_search(Budget::Investment) + end + + def filter_and_search(target) + target = target.unfeasible if params[:unfeasible].present? + target = target.by_geozone(params[:geozone]) if params[:geozone].present? + target = target.search(params[:search]) if params[:search].present? + target.page(params[:page]).for_render + end + + def load_geozone + return if params[:geozone].blank? + + if params[:geozone] == 'all' + @geozone_name = t('geozones.none') + else + @geozone_name = Geozone.find(params[:geozone]).name + end + end + + end +end \ No newline at end of file diff --git a/app/controllers/concerns/commentable_actions.rb b/app/controllers/concerns/commentable_actions.rb index de2a2276a..3a79238ea 100644 --- a/app/controllers/concerns/commentable_actions.rb +++ b/app/controllers/concerns/commentable_actions.rb @@ -11,6 +11,8 @@ module CommentableActions index_customization if index_customization.present? @tag_cloud = tag_cloud + @banners = Banner.with_active + set_resource_votes(@resources) set_resources_instance end diff --git a/app/controllers/concerns/feature_flags.rb b/app/controllers/concerns/feature_flags.rb index 9c96db96e..ca3cd929e 100644 --- a/app/controllers/concerns/feature_flags.rb +++ b/app/controllers/concerns/feature_flags.rb @@ -3,7 +3,7 @@ module FeatureFlags class_methods do def feature_flag(name, *options) - before_filter(*options) do + before_action(*options) do check_feature_flag(name) end end diff --git a/app/controllers/direct_messages_controller.rb b/app/controllers/direct_messages_controller.rb new file mode 100644 index 000000000..07f39d941 --- /dev/null +++ b/app/controllers/direct_messages_controller.rb @@ -0,0 +1,36 @@ +class DirectMessagesController < ApplicationController + load_and_authorize_resource + + def new + @receiver = User.find(params[:user_id]) + @direct_message = DirectMessage.new(receiver: @receiver) + end + + def create + @sender = current_user + @receiver = User.find(params[:user_id]) + + @direct_message = DirectMessage.new(parsed_params) + if @direct_message.save + Mailer.direct_message_for_receiver(@direct_message).deliver_later + Mailer.direct_message_for_sender(@direct_message).deliver_later + redirect_to [@receiver, @direct_message], notice: I18n.t("flash.actions.create.direct_message") + else + render :new + end + end + + def show + @direct_message = DirectMessage.find(params[:id]) + end + + private + + def direct_message_params + params.require(:direct_message).permit(:title, :body) + end + + def parsed_params + direct_message_params.merge(sender: @sender, receiver: @receiver) + end +end \ No newline at end of file diff --git a/app/controllers/management/proposals_controller.rb b/app/controllers/management/proposals_controller.rb index 4f6ca18c4..2ce74d6d5 100644 --- a/app/controllers/management/proposals_controller.rb +++ b/app/controllers/management/proposals_controller.rb @@ -13,6 +13,7 @@ class Management::ProposalsController < Management::BaseController def show super + @notifications = @proposal.notifications redirect_to management_proposal_path(@proposal), status: :moved_permanently if request.path != management_proposal_path(@proposal) end diff --git a/app/controllers/management/user_invites_controller.rb b/app/controllers/management/user_invites_controller.rb new file mode 100644 index 000000000..cbe3d1914 --- /dev/null +++ b/app/controllers/management/user_invites_controller.rb @@ -0,0 +1,13 @@ +class Management::UserInvitesController < Management::BaseController + + def new + end + + def create + @emails = params[:emails].split(",").map(&:strip) + @emails.each do |email| + Mailer.user_invite(email).deliver_later + end + end + +end diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb index a4ec31b50..ab346e802 100644 --- a/app/controllers/notifications_controller.rb +++ b/app/controllers/notifications_controller.rb @@ -9,7 +9,7 @@ class NotificationsController < ApplicationController def show @notification = current_user.notifications.find(params[:id]) - redirect_to url_for(@notification.notifiable) + redirect_to url_for(@notification.linkable_resource) end def mark_all_as_read diff --git a/app/controllers/proposal_notifications_controller.rb b/app/controllers/proposal_notifications_controller.rb new file mode 100644 index 000000000..fc9cdf3d8 --- /dev/null +++ b/app/controllers/proposal_notifications_controller.rb @@ -0,0 +1,33 @@ +class ProposalNotificationsController < ApplicationController + load_and_authorize_resource except: [:new] + + def new + @proposal = Proposal.find(params[:proposal_id]) + @notification = ProposalNotification.new(proposal_id: @proposal.id) + authorize! :new, @notification + end + + def create + @notification = ProposalNotification.new(proposal_notification_params) + @proposal = Proposal.find(proposal_notification_params[:proposal_id]) + if @notification.save + @proposal.voters.each do |voter| + Notification.add(voter.id, @notification) + end + redirect_to @notification, notice: I18n.t("flash.actions.create.proposal_notification") + else + render :new + end + end + + def show + @notification = ProposalNotification.find(params[:id]) + end + + private + + def proposal_notification_params + params.require(:proposal_notification).permit(:title, :body, :proposal_id) + end + +end \ No newline at end of file diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index 0b350f687..578395ab3 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -2,7 +2,6 @@ class ProposalsController < ApplicationController include CommentableActions include FlagActions - before_action :parse_search_terms, only: [:index, :suggest] before_action :parse_advanced_search_terms, only: :index before_action :parse_tag_filter, only: :index @@ -22,6 +21,7 @@ class ProposalsController < ApplicationController def show super + @notifications = @proposal.notifications redirect_to proposal_path(@proposal), status: :moved_permanently if request.path != proposal_path(@proposal) end diff --git a/app/controllers/spending_proposals_controller.rb b/app/controllers/spending_proposals_controller.rb index 3f590f414..5f8b04717 100644 --- a/app/controllers/spending_proposals_controller.rb +++ b/app/controllers/spending_proposals_controller.rb @@ -1,7 +1,7 @@ class SpendingProposalsController < ApplicationController include FeatureFlags - before_action :authenticate_user!, except: [:index] + before_action :authenticate_user!, except: [:index, :show] before_action -> { flash.now[:notice] = flash[:notice].html_safe if flash[:html_safe] && flash[:notice] } load_and_authorize_resource diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index af4005e06..fbd77f184 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -3,6 +3,7 @@ class UsersController < ApplicationController load_and_authorize_resource helper_method :authorized_for_filter? + helper_method :author? helper_method :author_or_admin? def show @@ -65,8 +66,12 @@ class UsersController < ApplicationController @user.public_activity || authorized_current_user? end + def author? + @author ||= current_user && (current_user == @user) + end + def author_or_admin? - @author_or_admin ||= current_user && (current_user == @user || current_user.administrator?) + @author_or_admin ||= current_user && (author? || current_user.administrator?) end def authorized_current_user? diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c5f2e6aca..1f52f0eea 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -35,4 +35,9 @@ module ApplicationHelper } Redcarpet::Markdown.new(renderer, extensions).render(text).html_safe end + + def author_of?(authorable, user) + return false if authorable.blank? || user.blank? + authorable.author_id == user.id + end end diff --git a/app/helpers/banners_helper.rb b/app/helpers/banners_helper.rb new file mode 100644 index 000000000..548513c7d --- /dev/null +++ b/app/helpers/banners_helper.rb @@ -0,0 +1,5 @@ +module BannersHelper + def has_banners + @banners.count > 0 + end +end \ No newline at end of file diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index 281163380..2b907535f 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -1,6 +1,4 @@ module NotificationsHelper - def notification_action(notification) - notification.notifiable_type == "Comment" ? "replies_to" : "comments_on" - end + end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index c1f3e4bb6..1dbc5baa2 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -1,5 +1,5 @@ class ApplicationMailer < ActionMailer::Base helper :settings - default from: "participacion@madrid.es" + default from: "Consul " layout 'mailer' end diff --git a/app/mailers/mailer.rb b/app/mailers/mailer.rb index 82abbb205..ad87359af 100644 --- a/app/mailers/mailer.rb +++ b/app/mailers/mailer.rb @@ -42,6 +42,38 @@ class Mailer < ApplicationMailer end end + def direct_message_for_receiver(direct_message) + @direct_message = direct_message + @receiver = @direct_message.receiver + + with_user(@receiver) do + mail(to: @receiver.email, subject: t('mailers.direct_message_for_receiver.subject')) + end + end + + def direct_message_for_sender(direct_message) + @direct_message = direct_message + @sender = @direct_message.sender + + with_user(@sender) do + mail(to: @sender.email, subject: t('mailers.direct_message_for_sender.subject')) + end + end + + def proposal_notification_digest(user) + @notifications = user.notifications.where(notifiable_type: "ProposalNotification") + + with_user(user) do + mail(to: user.email, subject: t('mailers.proposal_notification_digest.title', org_name: Setting['org_name'])) + end + end + + def user_invite(email) + I18n.with_locale(I18n.default_locale) do + mail(to: email, subject: t('mailers.user_invite.subject', org_name: Setting["org_name"])) + end + end + private def with_user(user, &block) diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb index b86723c93..42e4ecbd3 100644 --- a/app/models/abilities/administrator.rb +++ b/app/models/abilities/administrator.rb @@ -46,6 +46,8 @@ module Abilities can [:hide, :update], Budget::Investment can :valuate, Budget::Investment, budget: { valuating: true } can :create, Budget::ValuatorAssignment + + can [:search, :edit, :update, :create, :index, :destroy], Banner end end end diff --git a/app/models/abilities/common.rb b/app/models/abilities/common.rb index f2c5ec720..fb03cbea2 100644 --- a/app/models/abilities/common.rb +++ b/app/models/abilities/common.rb @@ -44,14 +44,19 @@ module Abilities can :vote_featured, Proposal can :vote, SpendingProposal can :create, SpendingProposal + can :create, Budget::Investment, budget: { phase: "accepting" } can :vote, Budget::Investment, budget: { phase: "selecting" } can :create, Budget::Ballot, budget: { phase: "balloting" } + + can :create, DirectMessage + can :show, DirectMessage, sender_id: user.id end + can [:create, :show], ProposalNotification, proposal: { author_id: user.id } + can :create, Annotation can [:update, :destroy], Annotation, user_id: user.id - end end end diff --git a/app/models/abilities/everyone.rb b/app/models/abilities/everyone.rb index 327210de8..561ac5994 100644 --- a/app/models/abilities/everyone.rb +++ b/app/models/abilities/everyone.rb @@ -12,6 +12,9 @@ module Abilities can :read, Legislation can :read, User can [:search, :read], Annotation + can [:read], Budget + can [:read], Budget::Investment + can :new, DirectMessage end end end diff --git a/app/models/banner.rb b/app/models/banner.rb new file mode 100644 index 000000000..db8f10635 --- /dev/null +++ b/app/models/banner.rb @@ -0,0 +1,20 @@ +class Banner < ActiveRecord::Base + + acts_as_paranoid column: :hidden_at + include ActsAsParanoidAliases + + validates :title, presence: true, + length: { minimum: 2 } + validates :description, presence: true + validates :target_url, presence: true + validates :style, presence: true + validates :image, presence: true + validates :post_started_at, presence: true + validates :post_ended_at, presence: true + + scope :with_active, -> {where("post_started_at <= ?", Time.now). + where("post_ended_at >= ?", Time.now) } + + scope :with_inactive,-> {where("post_started_at > ? or post_ended_at < ?", Time.now, Time.now) } + +end \ No newline at end of file diff --git a/app/models/budget.rb b/app/models/budget.rb index dfcba3214..c79210b18 100644 --- a/app/models/budget.rb +++ b/app/models/budget.rb @@ -7,9 +7,11 @@ class Budget < ActiveRecord::Base validates :phase, inclusion: { in: VALID_PHASES } validates :currency_symbol, presence: true - has_many :investments - has_many :ballots - has_many :headings + has_many :investments, dependent: :destroy + has_many :ballots, dependent: :destroy + has_many :groups, dependent: :destroy + has_many :headings, through: :groups + has_many :investments, through: :headings def on_hold? phase == "on_hold" @@ -32,7 +34,6 @@ class Budget < ActiveRecord::Base end def heading_price(heading) - return price unless heading.present? heading_ids.include?(heading.id) ? heading.price : -1 end end diff --git a/app/models/budget/ballot.rb b/app/models/budget/ballot.rb index db4017285..848e2f22d 100644 --- a/app/models/budget/ballot.rb +++ b/app/models/budget/ballot.rb @@ -2,11 +2,14 @@ class Budget class Ballot < ActiveRecord::Base belongs_to :user belongs_to :budget - belongs_to :heading has_many :lines, dependent: :destroy has_many :investments, through: :lines + def add_investment(investment) + lines.create!(budget: budget, investment: investment, heading: investment.heading, group_id: investment.heading.group_id) + end + def total_amount_spent investments.sum(:price).to_i end @@ -16,7 +19,17 @@ class Budget end def amount_available(heading) - budget.heading_price(heading) - amount_spent(heading.try(:id)) + budget.heading_price(heading) - amount_spent(heading.id) + end + + def valid_heading?(heading) + group = heading.group + return false if group.budget_id != budget_id + + line = lines.where(heading_id: group.heading_ids).first + return false if line.present? && line.heading_id != heading.id + + true end def has_lines_with_no_heading? diff --git a/app/models/budget/ballot/line.rb b/app/models/budget/ballot/line.rb index 887951922..01835cd90 100644 --- a/app/models/budget/ballot/line.rb +++ b/app/models/budget/ballot/line.rb @@ -2,11 +2,15 @@ class Budget class Ballot class Line < ActiveRecord::Base belongs_to :ballot + belongs_to :budget + belongs_to :group + belongs_to :heading belongs_to :investment validate :insufficient_funds validate :different_geozone, :if => :district_proposal? validate :unfeasible + #needed? validates :ballot_id, :budget_id, :group_id, :heading_id, :investment_id, presence: true def insufficient_funds errors.add(:money, "") if ballot.amount_available(investment.heading) < investment.price.to_i @@ -23,7 +27,6 @@ class Budget def heading_proposal? investment.heading_id.present? end - end end end diff --git a/app/models/budget/group.rb b/app/models/budget/group.rb new file mode 100644 index 000000000..dd7910950 --- /dev/null +++ b/app/models/budget/group.rb @@ -0,0 +1,10 @@ +class Budget + class Group < ActiveRecord::Base + belongs_to :budget + + has_many :headings, dependent: :destroy + + validates :budget_id, presence: true + validates :name, presence: true + end +end \ No newline at end of file diff --git a/app/models/budget/heading.rb b/app/models/budget/heading.rb index e79c5b7c8..830596912 100644 --- a/app/models/budget/heading.rb +++ b/app/models/budget/heading.rb @@ -1,11 +1,11 @@ class Budget class Heading < ActiveRecord::Base - belongs_to :budget + belongs_to :group belongs_to :geozone has_many :investments - validates :budget_id, presence: true + validates :group_id, presence: true validates :name, presence: true validates :price, presence: true end diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index 43b0fde2f..bbdc0e73e 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -10,7 +10,6 @@ class Budget acts_as_paranoid column: :hidden_at include ActsAsParanoidAliases - belongs_to :budget belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id' belongs_to :heading belongs_to :administrator @@ -22,6 +21,7 @@ class Budget validates :title, presence: true validates :author, presence: true validates :description, presence: true + validates :heading_id, presence: true validates_presence_of :unfeasibility_explanation, if: :unfeasibility_explanation_required? validates :title, length: { in: 4 .. Budget::Investment.title_max_length } @@ -44,16 +44,12 @@ class Budget scope :with_supports, -> { where('cached_votes_up > 0') } scope :by_heading, -> (heading_id) { where(heading_id: heading_id) } - scope :by_budget, -> (budget_id) { where(budget_id: budget_id) } scope :by_admin, -> (admin_id) { where(administrator_id: admin_id) } scope :by_tag, -> (tag_name) { tagged_with(tag_name) } scope :by_valuator, -> (valuator_id) { where("budget_valuator_assignments.valuator_id = ?", valuator_id).joins(:valuator_assignments) } scope :for_render, -> { includes(heading: :geozone) } - scope :with_heading, -> { where.not(heading_id: nil) } - scope :no_heading, -> { where(heading_id: nil) } - before_save :calculate_confidence_score before_validation :set_responsible_name @@ -62,8 +58,7 @@ class Budget end def self.scoped_filter(params, current_filter) - budget = Budget.find!(params[:budget_id]) - results = self.by_budget(params[:budget_id]) + results = budget.investments if params[:max_for_no_heading].present? || params[:max_per_heading].present? results = limit_results(results, budget, params[:max_per_heading].to_i, params[:max_for_no_heading].to_i) end @@ -119,6 +114,10 @@ class Budget where(heading_id: heading == 'all' ? nil : heading.presence) end + def budget + heading.group.budget + end + def undecided? feasibility == "undecided" end @@ -140,7 +139,7 @@ class Budget end def code - "B#{budget_id}I#{id}" + "B#{budget.id}I#{id}" end def reason_for_not_being_selectable_by(user) @@ -152,7 +151,7 @@ class Budget def reason_for_not_being_ballotable_by(user, ballot) return permission_problem(user) if permission_problem?(user) return :no_ballots_allowed unless budget.balloting? - return :different_heading_assigned unless heading_id.blank? || ballot.blank? || heading_id == ballot.heading_id || ballot.heading_id.nil? + return :different_heading_assigned unless ballot.valid_heading?(heading) return :not_enough_money if ballot.present? && !enough_money?(ballot) end diff --git a/app/models/direct_message.rb b/app/models/direct_message.rb new file mode 100644 index 000000000..476194aea --- /dev/null +++ b/app/models/direct_message.rb @@ -0,0 +1,22 @@ +class DirectMessage < ActiveRecord::Base + belongs_to :sender, class_name: 'User', foreign_key: 'sender_id' + belongs_to :receiver, class_name: 'User', foreign_key: 'receiver_id' + + validates :title, presence: true + validates :body, presence: true + validates :sender, presence: true + validates :receiver, presence: true + validate :max_per_day + + scope :today, lambda { where('DATE(created_at) = ?', Date.today) } + + def max_per_day + return if errors.any? + max = Setting[:direct_message_max_per_day] + + if sender.direct_messages_sent.today.count >= max.to_i + errors.add(:title, I18n.t('activerecord.errors.models.direct_message.attributes.max_per_day.invalid')) + end + end + +end diff --git a/app/models/notification.rb b/app/models/notification.rb index 1cb500ccf..9695c1b01 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -21,4 +21,30 @@ class Notification < ActiveRecord::Base Notification.create!(user_id: user_id, notifiable: notifiable) end end + + def notifiable_title + case notifiable.class.name + when "ProposalNotification" + notifiable.proposal.title + when "Comment" + notifiable.commentable.title + else + notifiable.title + end + end + + def notifiable_action + case notifiable_type + when "ProposalNotification" + "proposal_notification" + when "Comment" + "replies_to" + else + "comments_on" + end + end + + def linkable_resource + notifiable.is_a?(ProposalNotification) ? notifiable.proposal : notifiable + end end \ No newline at end of file diff --git a/app/models/proposal.rb b/app/models/proposal.rb index dd310dffa..b6a8ddb26 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -16,6 +16,7 @@ class Proposal < ActiveRecord::Base belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id' belongs_to :geozone has_many :comments, as: :commentable + has_many :proposal_notifications validates :title, presence: true validates :question, presence: true @@ -93,6 +94,10 @@ class Proposal < ActiveRecord::Base cached_votes_up + physical_votes end + def voters + votes_for.voters + end + def editable? total_votes <= Setting["max_votes_for_proposal_edit"].to_i end @@ -146,6 +151,10 @@ class Proposal < ActiveRecord::Base Setting['votes_for_proposal_success'].to_i end + def notifications + proposal_notifications + end + protected def set_responsible_name diff --git a/app/models/proposal_notification.rb b/app/models/proposal_notification.rb new file mode 100644 index 000000000..f73264318 --- /dev/null +++ b/app/models/proposal_notification.rb @@ -0,0 +1,17 @@ +class ProposalNotification < ActiveRecord::Base + belongs_to :author, class_name: 'User', foreign_key: 'author_id' + belongs_to :proposal + + validates :title, presence: true + validates :body, presence: true + validates :proposal, presence: true + validate :minimum_interval + + def minimum_interval + return true if proposal.try(:notifications).blank? + if proposal.notifications.last.created_at > (Time.now - Setting[:proposal_notification_minimum_interval_in_days].to_i.days).to_datetime + errors.add(:title, I18n.t('activerecord.errors.models.proposal_notification.attributes.minimum_interval.invalid', interval: Setting[:proposal_notification_minimum_interval_in_days])) + end + end + +end \ No newline at end of file diff --git a/app/models/setting.rb b/app/models/setting.rb index 40659ed74..9010abba5 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -2,6 +2,20 @@ class Setting < ActiveRecord::Base validates :key, presence: true, uniqueness: true default_scope { order(id: :asc) } + scope :banner_style, -> { where("key ilike ?", "banner-style.%")} + scope :banner_img, -> { where("key ilike ?", "banner-img.%")} + + def type + if feature_flag? + 'feature' + elsif banner_style? + 'banner-style' + elsif banner_img? + 'banner-img' + else + 'common' + end + end def feature_flag? key.start_with?('feature.') @@ -11,6 +25,14 @@ class Setting < ActiveRecord::Base feature_flag? && value.present? end + def banner_style? + key.start_with?('banner-style.') + end + + def banner_img? + key.start_with?('banner-img.') + end + class << self def [](key) where(key: key).pluck(:value).first.presence diff --git a/app/models/user.rb b/app/models/user.rb index 8da62dd0d..bf252a6fc 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -23,6 +23,8 @@ class User < ActiveRecord::Base has_many :spending_proposals, foreign_key: :author_id has_many :failed_census_calls has_many :notifications + has_many :direct_messages_sent, class_name: 'DirectMessage', foreign_key: :sender_id + has_many :direct_messages_received, class_name: 'DirectMessage', foreign_key: :receiver_id belongs_to :geozone validates :username, presence: true, if: :username_required? @@ -50,6 +52,7 @@ class User < ActiveRecord::Base scope :officials, -> { where("official_level > 0") } scope :for_render, -> { includes(:organization) } scope :by_document, -> (document_type, document_number) { where(document_type: document_type, document_number: document_number) } + scope :email_digest, -> { where(email_digest: true) } before_validation :clean_document_number @@ -135,6 +138,16 @@ class User < ActiveRecord::Base update official_position: nil, official_level: 0 end + def has_official_email? + domain = Setting['email_domain_for_officials'] + !email.blank? && ( (email.end_with? "@#{domain}") || (email.end_with? ".#{domain}") ) + end + + def display_official_position_badge? + return true if official_level > 1 + official_position_badge? && official_level == 1 + end + def block debates_ids = Debate.where(author_id: id).pluck(:id) comments_ids = Comment.where(user_id: id).pluck(:id) @@ -199,11 +212,6 @@ class User < ActiveRecord::Base !erased? end - def has_official_email? - domain = Setting['email_domain_for_officials'] - !email.blank? && ( (email.end_with? "@#{domain}") || (email.end_with? ".#{domain}") ) - end - def locale self[:locale] ||= I18n.default_locale.to_s end diff --git a/app/views/account/show.html.erb b/app/views/account/show.html.erb index f0d2b6abc..247aa6024 100644 --- a/app/views/account/show.html.erb +++ b/app/views/account/show.html.erb @@ -34,7 +34,9 @@
<%= f.label :public_activity do %> <%= f.check_box :public_activity, title: t('account.show.public_activity_label'), label: false %> - <%= t("account.show.public_activity_label") %> + + <%= t("account.show.public_activity_label") %> + <% end %>
@@ -43,24 +45,61 @@
<%= f.label :email_on_comment do %> <%= f.check_box :email_on_comment, title: t('account.show.email_on_comment_label'), label: false %> - <%= t("account.show.email_on_comment_label") %> + + <%= t("account.show.email_on_comment_label") %> + <% end %>
<%= f.label :email_on_comment_reply do %> <%= f.check_box :email_on_comment_reply, title: t('account.show.email_on_comment_reply_label'), label: false %> - <%= t("account.show.email_on_comment_reply_label") %> + + <%= t("account.show.email_on_comment_reply_label") %> + <% end %>
<%= f.label :email_newsletter_subscribed do %> <%= f.check_box :newsletter, title: t('account.show.subscription_to_website_newsletter_label'), label: false %> - <%= t("account.show.subscription_to_website_newsletter_label") %> + + <%= t("account.show.subscription_to_website_newsletter_label") %> + <% end %>
+
+ <%= f.label :email_digest do %> + <%= f.check_box :email_digest, title: t('account.show.email_digest_label'), label: false %> + + <%= t("account.show.email_digest_label") %> + + <% end %> +
+ +
+ <%= f.label :email_on_direct_message do %> + <%= f.check_box :email_on_direct_message, title: t('account.show.email_on_direct_message_label'), label: false %> + + <%= t("account.show.email_on_direct_message_label") %> + + <% end %> +
+ + <% if @account.official_level == 1 %> +
+ <%= f.label :official_position_badge do %> + <%= f.check_box :official_position_badge, + title: t('account.show.official_position_badge_label'), + label: false %> + + <%= t("account.show.official_position_badge_label") %> + + <% end %> +
+ <% end %> + <%= f.submit t("account.show.save_changes_submit"), class: "button" %> diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index bf0382dbd..7ea48b2c6 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -1,115 +1,103 @@