diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index bcadd2a25..4704696e5 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -42,7 +42,6 @@ Layout/DotPosition: - 'app/controllers/admin/poll/officer_assignments_controller.rb' - 'app/controllers/admin/poll/polls_controller.rb' - 'app/controllers/admin/poll/recounts_controller.rb' - - 'app/controllers/officing/final_recounts_controller.rb' - 'app/controllers/officing/residence_controller.rb' - 'app/controllers/officing/results_controller.rb' - 'app/models/poll/officer.rb' @@ -191,7 +190,6 @@ Layout/MultilineMethodCallIndentation: - 'app/controllers/admin/poll/officer_assignments_controller.rb' - 'app/controllers/admin/poll/polls_controller.rb' - 'app/controllers/admin/poll/recounts_controller.rb' - - 'app/controllers/officing/final_recounts_controller.rb' - 'app/controllers/officing/residence_controller.rb' - 'app/controllers/officing/results_controller.rb' - 'app/models/poll/officer.rb' @@ -289,6 +287,7 @@ Lint/StringConversionInInterpolation: - 'app/models/poll/null_result.rb' - 'app/models/poll/partial_result.rb' - 'app/models/poll/white_result.rb' + - 'app/models/poll/total_result.rb' # Offense count: 15 # Cop supports --auto-correct. @@ -473,7 +472,6 @@ Style/ConditionalAssignment: - 'app/controllers/admin/poll/questions_controller.rb' - 'app/controllers/comments_controller.rb' - 'app/controllers/management/spending_proposals_controller.rb' - - 'app/controllers/officing/final_recounts_controller.rb' - 'app/controllers/spending_proposals_controller.rb' - 'app/controllers/verification/sms_controller.rb' - 'lib/graph_ql/api_types_creator.rb' @@ -565,6 +563,7 @@ Style/MutableConstant: - 'app/models/poll/null_result.rb' - 'app/models/poll/partial_result.rb' - 'app/models/poll/white_result.rb' + - 'app/models/poll/total_result.rb' - 'app/models/proposal.rb' - 'app/models/signature_sheet.rb' - 'app/models/site_customization/content_block.rb' diff --git a/.travis.yml b/.travis.yml index 7d5f6169a..8836964a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ before_script: - "for i in config/*.example; do cp \"$i\" \"${i/.example}\"; done" - bundle exec rake db:setup script: + - "bundle exec rake assets:precompile RAILS_ENV=test" - "bundle exec rake knapsack:rspec" env: global: diff --git a/CUSTOMIZE_EN.md b/CUSTOMIZE_EN.md deleted file mode 100644 index 3a97b96de..000000000 --- a/CUSTOMIZE_EN.md +++ /dev/null @@ -1,221 +0,0 @@ -# Customization - -You can modify your own CONSUL to have your custom visual style, but first you'll have to create a fork from [https://github.com/consul/consul](https://github.com/consul/consul) using Github's "fork" button on top right corner. You can use any other service like Gitlab, but don't forget to put a reference link back to CONSUL on the footer to comply with project's license (GPL Affero 3). - -We've created an specific structure where you can overwrite and customize the application in a way that will let you keep updating it from CONSUL's main repository, without having conflicts on code merging or risking loosing your customization changes. We try to make CONSUL as vanilla as possible to help other developers onboard the codebase. - -## Special Folders and Files - -In order to customize your CONSUL fork, you'll make use of some `custom` folders on the following paths: - -* `config/locales/custom/` -* `app/assets/images/custom/` -* `app/views/custom/` -* `app/controllers/custom/` -* `app/models/custom/` - -Also these are the files where you can apply some customization: - -* `app/assets/stylesheets/custom.css` -* `app/assets/stylesheets/_custom_settings.css` -* `app/assets/javascripts/custom.js` -* `Gemfile_custom` -* `config/application.custom.rb` - -### Internationalization - -If you want to add a new language translation of the user-facing texts you can find them organized in YML files under `config/locales/` folder. Take a look at the official Ruby on Rails [internationalization guide](http://guides.rubyonrails.org/i18n.html) to better understand the translations system. - -If you just want to change some of the existing texts, you can just drop your changes at the `config/locales/custom/` folder, we strongly recommend to include only those text that you want to change instead of a whole copy of the original file. For example if you want to customize the text "Ayuntamiento de Madrid, 2016" that appears on every page's footer, firstly you want to locate where it's used (`app/views/layouts/_footer.html.erb`), we can see code is: - -```ruby -<%= t("layouts.footer.copyright", year: Time.current.year) %> -``` - -And that the text its located at the file `config/locales/es/general.yml` following this structure (we're only displaying in the following snippet the relevant parts): - -```yml -es: - layouts: - footer: - copyright: Ayuntamiento de Madrid, %{year} - -``` - -So in order to customize it, we would create a new file `config/locales/custom/es/general.yml` with just that content, and change "Ayuntamiento de Madrid" for our organization name. We strongly recommend to make copies from `config/locales/` and modify or delete the lines as needed to keep the indentation structure and avoid issues. - -### Images - -If you want to overwrite any image, firstly you need to findout the filename, and by defaul it will be located under `app/assets/images`. For example if you want to change the header logo (`app/assets/images/logo_header.png`) you must create another file with the exact same file name under `app/assets/images/custom` folder. The images and icons that you will most likely want to change are: - -* apple-touch-icon-200.png -* icon_home.png -* logo_email.png -* logo_header.png -* map.jpg -* social_media_icon.png -* social_media_icon_twitter.png - -### Views (HTML) - -If you want to change any page HTML you can just find the correct file under the `app/views` folder and put a copy at `app/views/custom` keeping as well any sub-folder structure, and then apply your customizations. For example if you want to customize `app/views/pages/conditions.html` you'll have to make a copy at `app/views/custom/pages/conditions.html.erb` (note the `pages` subdirectory). - -### CSS - -In order to make changes to any CSS selector (custom style sheets), you can add them directly at `app/assets/stylesheets/custom.scss`. For example to change the header color (`.top-links`) you can just add: - -```css -.top-links { - background: red; -} -``` - -If you want to change any [foundation](http://foundation.zurb.com/) variable, you can do it at the `app/assets/stylesheets/_custom_settings.scss` file. For example to change the main application color just add: - -```css -$brand: #446336; -``` - -We use [SASS, with SCSS syntax](http://sass-lang.com/guide) as CSS preprocessor. - -### Javascript - -If you want to add some custom Javascript code, `app/assets/javascripts/custom.js` is the file to do it. For example to create a new alert just add: - -```js -$(function(){ - alert('foobar'); -}); -``` - -### Models - -If you need to create new models or customize existent ones, you can do it so at the `app/models/custom` folder. Keep in mind that for old models you'll need to firstly require the dependency. - -For example for Madrid's City Hall fork its required to check the zip code's format (it always starts with 280 followed by 2 digits). That check is at `app/models/custom/verification/residence.rb`: - -```ruby -require_dependency Rails.root.join('app', 'models', 'verification', 'residence').to_s - -class Verification::Residence - - validate :postal_code_in_madrid - validate :residence_in_madrid - - def postal_code_in_madrid - errors.add(:postal_code, I18n.t('verification.residence.new.error_not_allowed_postal_code')) unless valid_postal_code? - end - - def residence_in_madrid - return if errors.any? - - unless residency_valid? - errors.add(:residence_in_madrid, false) - store_failed_attempt - Lock.increase_tries(user) - end - end - - private - - def valid_postal_code? - postal_code =~ /^280/ - end - -end -``` - -Do not forget to cover your changes with a test at the `spec/models/custom` folder. Following the example we could create `spec/models/custom/residence_spec.rb`: - -```ruby -require 'rails_helper' - -describe Verification::Residence do - - let(:residence) { build(:verification_residence, document_number: "12345678Z") } - - describe "verification" do - - describe "postal code" do - it "should be valid with postal codes starting with 280" do - residence.postal_code = "28012" - residence.valid? - expect(residence.errors[:postal_code].size).to eq(0) - - residence.postal_code = "28023" - residence.valid? - expect(residence.errors[:postal_code].size).to eq(0) - end - - it "should not be valid with postal codes not starting with 280" do - residence.postal_code = "12345" - residence.valid? - expect(residence.errors[:postal_code].size).to eq(1) - - residence.postal_code = "13280" - residence.valid? - expect(residence.errors[:postal_code].size).to eq(1) - expect(residence.errors[:postal_code]).to include("In order to be verified, you must be registered in the municipality of Madrid.") - end - end - - end - -end -``` - -### Controllers - -TODO! - -### Gemfile - -To add new gems (libraries) you can edit the `Gemfile_custom` file. For example to add [rails-footnotes](https://github.com/josevalim/rails-footnotes) gem you would just add: - -```ruby -gem 'rails-footnotes', '~> 4.0' -``` - -And then just do the classic Ruby on Rails flow `bundle install` and following any gem specific install steps from it's own documentation. - -### application.rb - -If you need to extend or modify the `config/application.rb` just do it at the `config/application_custom.rb` file. For example if you want to change de default language to English, just add: - -```ruby -module Consul - class Application < Rails::Application - config.i18n.default_locale = :en - config.i18n.available_locales = [:en, :es] - end -end -``` - -Remeber that in order to see this changes live you'll need to restart the server. - -### lib/ - -TODO - -### public/ - -TODO - -### Seeds - -TODO - -## Updating - -We recommend you to add CONSUL as remote: - -``` -git remote add consul https://github.com/consul/consul -``` - -And then just grab lastest changes on to a branch of your own repo with: - -``` -git checkout -b consul_update -git pull consul master -``` diff --git a/CUSTOMIZE_ES.md b/CUSTOMIZE_ES.md deleted file mode 100644 index 26204c4e4..000000000 --- a/CUSTOMIZE_ES.md +++ /dev/null @@ -1,221 +0,0 @@ -# Personalización - -Puedes modificar CONSUL y ponerle tu propia imagen, para esto debes primero hacer un fork de [https://github.com/consul/consul](https://github.com/consul/consul) creando un repositorio nuevo en Github. Puedes usar otro servicio como Gitlab, pero no te olvides de poner el enlace en el footer a tu repositorio en cumplimiento con la licencia de este proyecto (GPL Affero 3). - -Hemos creado una estructura específica donde puedes sobreescribir y personalizar la aplicación para que puedas actualizar sin que tengas problemas al hacer merge y se sobreescriban por error tus cambios. Intentamos que CONSUL sea una aplicación Ruby on Rails lo más plain vanilla posible para facilitar el acceso de nuevas desarrolladoras. - -## Ficheros y directorios especiales - -Para adaptar tu fork de CONSUL puedes utilizar alguno de los directorios `custom` que están en las rutas: - -* `config/locales/custom/` -* `app/assets/images/custom/` -* `app/views/custom/` -* `app/controllers/custom/` -* `app/models/custom/` - -Aparte de estos directorios también cuentas con ciertos ficheros para: - -* `app/assets/stylesheets/custom.css` -* `app/assets/stylesheets/_custom_settings.css` -* `app/assets/javascripts/custom.js` -* `Gemfile_custom` -* `config/application.custom.rb` - -### Internacionalización - -Si quieres modificar algún texto de la web deberías encontrarlos en los ficheros formato YML disponibles en `config/locales/`. Puedes leer la [guía de internacionalización](http://guides.rubyonrails.org/i18n.html) de Ruby on Rails sobre como funciona este sistema. - -Las adaptaciones los debes poner en el directorio `config/locales/custom/`, recomendamos poner solo los textos que quieras personalizar. Por ejemplo si quieres personalizar el texto de "Ayuntamiento de Madrid, 2016" que se encuentra en el footer en todas las páginas, primero debemos ubicar en que plantilla se encuentra (`app/views/layouts/_footer.html.erb`), vemos que en el código pone lo siguiente: - -```ruby -<%= t("layouts.footer.copyright", year: Time.current.year) %> -``` - -Y que en el fichero `config/locales/es/general.yml` sigue esta estructura (solo ponemos lo relevante para este caso): - -```yml -es: - layouts: - footer: - copyright: Ayuntamiento de Madrid, %{year} - -``` - -Si creamos el fichero `config/locales/custom/es/general.yml` y modificamos "Ayuntamiento de Madrid" por el nombre de la organización que se este haciendo la modificación. Recomendamos directamente copiar los ficheros `config/locales/` e ir revisando y corrigiendo las que querramos, borrando las líneas que no querramos traducir. - -### Imágenes - -Si quieres sobreescribir alguna imagen debes primero fijarte el nombre que tiene, por defecto se encuentran en `app/assets/images`. Por ejemplo si quieres modificar `app/assets/images/logo_header.png` debes poner otra con ese mismo nombre en el directorio `app/assets/images/custom`. Los iconos que seguramente quieras modificar son: - -* apple-touch-icon-200.png -* icon_home.png -* logo_email.png -* logo_header.png -* map.jpg -* social_media_icon.png -* social_media_icon_twitter.png - -### Vistas (HTML) - -Si quieres modificar el HTML de alguna página puedes hacerlo copiando el HTML de `app/views` y poniendolo en `app/views/custom` respetando los subdirectorios que encuentres ahí. Por ejemplo si quieres modificar `app/views/pages/conditions.html` debes copiarlo y modificarla en `app/views/custom/pages/conditions.html.erb` - -### CSS - -Si quieres cambiar algun selector CSS (de las hojas de estilo) puedes hacerlo en el fichero `app/assets/stylesheets/custom.scss`. Por ejemplo si quieres cambiar el color del header (`.top-links`) puedes hacerlo agregando: - -```css -.top-links { - background: red; -} -``` - -Si quieres cambiar alguna variable de [foundation](http://foundation.zurb.com/) puedes hacerlo en el fichero `app/assets/stylesheets/_custom_settings.scss`. Por ejemplo para cambiar el color general de la aplicación puedes hacerlo agregando: - -```css -$brand: #446336; -``` - -Usamos un preprocesador de CSS, [SASS, con la sintaxis SCSS](http://sass-lang.com/guide). - -### Javascript - -Si quieres agregar código Javascript puedes hacerlo en el fichero `app/assets/javascripts/custom.js`. Por ejemplo si quieres que salga una alerta puedes poner lo siguiente: - -```js -$(function(){ - alert('foobar'); -}); -``` - -### Modelos - -Si quieres agregar modelos nuevos, o modificar o agregar métodos a uno ya existente puedes hacerlo en `app/models/custom`. En el caso de los modelos antiguos debes primero hacer un require de la dependencia. - -Por ejemplo en el caso del Ayuntamiento de Madrid se requiere comprobar que el código postal durante la verificación sigue un cierto formato (empieza con 280). Esto se realiza creando este fichero en `app/models/custom/verification/residence.rb`: - -```ruby -require_dependency Rails.root.join('app', 'models', 'verification', 'residence').to_s - -class Verification::Residence - - validate :postal_code_in_madrid - validate :residence_in_madrid - - def postal_code_in_madrid - errors.add(:postal_code, I18n.t('verification.residence.new.error_not_allowed_postal_code')) unless valid_postal_code? - end - - def residence_in_madrid - return if errors.any? - - unless residency_valid? - errors.add(:residence_in_madrid, false) - store_failed_attempt - Lock.increase_tries(user) - end - end - - private - - def valid_postal_code? - postal_code =~ /^280/ - end - -end -``` - -No olvides poner los tests relevantes en `spec/models/custom`, siguiendo con el ejemplo pondriamos lo siguiente en `spec/models/custom/residence_spec.rb`: - -```ruby -require 'rails_helper' - -describe Verification::Residence do - - let(:residence) { build(:verification_residence, document_number: "12345678Z") } - - describe "verification" do - - describe "postal code" do - it "should be valid with postal codes starting with 280" do - residence.postal_code = "28012" - residence.valid? - expect(residence.errors[:postal_code].size).to eq(0) - - residence.postal_code = "28023" - residence.valid? - expect(residence.errors[:postal_code].size).to eq(0) - end - - it "should not be valid with postal codes not starting with 280" do - residence.postal_code = "12345" - residence.valid? - expect(residence.errors[:postal_code].size).to eq(1) - - residence.postal_code = "13280" - residence.valid? - expect(residence.errors[:postal_code].size).to eq(1) - expect(residence.errors[:postal_code]).to include("In order to be verified, you must be registered in the municipality of Madrid.") - end - end - - end - -end -``` - -### Controladores - -TODO - -### Gemfile - -Para agregar librerías (gems) nuevas puedes hacerlo en el fichero `Gemfile_custom`. Por ejemplo si quieres agregar la gema [rails-footnotes](https://github.com/josevalim/rails-footnotes) debes hacerlo agregandole - -```ruby -gem 'rails-footnotes', '~> 4.0' -``` - -Y siguiendo el flujo clásico en Ruby on Rails (`bundle install` y seguir con los pasos específicos de la gema en la documentación) - -### application.rb - -Cuando necesites extender o modificar el `config/application.rb` puedes hacerlo a través del fichero `config/application_custom.rb`. Por ejemplo si quieres modificar el idioma por defecto al inglés pondrías lo siguiente: - -```ruby -module Consul - class Application < Rails::Application - config.i18n.default_locale = :en - config.i18n.available_locales = [:en, :es] - end -end -``` - -Recuerda que para ver reflejado estos cambios debes reiniciar el servidor de desarrollo. - -### lib/ - -TODO - -### public/ - -TODO - -### Seeds - -TODO - -## Actualizar - -Te recomendamos que agregues el remote de CONSUL para facilitar este proceso de merge: - -``` -git remote add consul https://github.com/consul/consul -``` - -Con esto puedes actualizarte con - -``` -git checkout -b consul_update -git pull consul master -``` diff --git a/Gemfile b/Gemfile index 3f17d753b..a6c1dc71e 100644 --- a/Gemfile +++ b/Gemfile @@ -24,6 +24,7 @@ gem 'graphql', '~> 1.6.3' gem 'groupdate', '~> 3.2.0' gem 'initialjs-rails', '~> 0.2.0.5' gem 'invisible_captcha', '~> 0.9.2' +gem 'jquery-fileupload-rails' gem 'jquery-rails', '~> 4.3.1' gem 'jquery-ui-rails', '~> 6.0.1' gem 'kaminari', '~> 1.0.1' @@ -33,7 +34,6 @@ gem 'omniauth-facebook', '~> 4.0.0' gem 'omniauth-google-oauth2', '~> 0.4.0' gem 'omniauth-twitter', '~> 1.4.0' gem 'paperclip', '~> 5.1.0' -gem 'jquery-fileupload-rails' gem 'paranoia', '~> 2.3.1' gem 'pg', '~> 0.21.0' gem 'pg_search', '~> 2.0.1' diff --git a/README.md b/README.md index 6b8eed086..48f6bfcb8 100644 --- a/README.md +++ b/README.md @@ -23,25 +23,20 @@ This is the opensource code repository of the eParticipation website CONSUL, ori 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 [features]( http://www.decide.es/en/) or [docs](https://github.com/consul/consul/tree/master/doc) and future features in the [open issues list](https://github.com/consul/consul/issues). For current status on upcoming features go to [Roadmap](https://github.com/consul/consul/projects/6) -## Tech stack - -The application backend is written in the [Ruby language](https://www.ruby-lang.org/) using the [Ruby on Rails](http://rubyonrails.org/) framework. - -Frontend tools used include [SCSS](http://sass-lang.com/) over [Foundation](http://foundation.zurb.com/) for the styles. - ## Configuration for development and test environments -**NOTE**: For more detailed instructions check the [docs](https://github.com/consul/consul/tree/master/doc/en/dev_test_setup.md) +**NOTE**: For more detailed instructions check the [docs](https://github.com/consul/docs/tree/master/en/getting_started/prerequisites) Prerequisites: install git, Ruby 2.3.2, bundler gem, and PostgreSQL (>=9.4). -``` +```bash git clone https://github.com/consul/consul.git cd consul bundle install cp config/database.yml.example config/database.yml cp config/secrets.yml.example config/secrets.yml -bin/rake db:setup +bin/rake db:create +bin/rake db:migrate bin/rake db:dev_seed RAILS_ENV=test rake db:setup ``` @@ -60,20 +55,6 @@ Run the tests with: bin/rspec ``` -If you add SCSS code you can check it with: - -``` -scss-lint -``` - -To maintain accesibility level, if you add new colors use a [Color contrast checker](http://webaim.org/resources/contrastchecker/) (WCAG AA is mandatory, WCAG AAA is recommended) - -If you work on Coffeescript code you can check it with [coffeelint](http://www.coffeelint.org/) (install with `npm install -g coffeelint`) : - -``` -coffeelint . -``` - You can use the default admin user from the seeds file: **user:** admin@consul.dev @@ -84,18 +65,9 @@ But for some actions like voting, you will need a verified user, the seeds file **user:** verified@consul.dev **pass:** 12345678 -### Customization +## Documentation -Read more on documentation: - -* English: [CUSTOMIZE_EN.md](CUSTOMIZE_EN.md) -* Spanish: [CUSTOMIZE_ES.md](CUSTOMIZE_ES.md) - -### OAuth - -To test authentication services with external OAuth suppliers - right now Twitter, Facebook and Google - you'll need to create an "application" in each of the supported platforms and set the *key* and *secret* provided in your *secrets.yml* - -In the case of Google, verify that the APIs *Contacts API* and *Google+ API* are enabled for the application. +Please check the ongoing documentation at https://consul_docs.gitbooks.io/docs/content/ to learn more about how to start your own CONSUL fork, install it, customize it and learn to use it from an administrator/maintainer perspective. You can contribute to it at https://github.com/consul/docs ## License @@ -104,7 +76,3 @@ Code published under AFFERO GPL v3 (see [LICENSE-AGPLv3.txt](LICENSE-AGPLv3.txt) ## Contributions See [CONTRIBUTING.md](CONTRIBUTING.md) - -## Brand guidelines - -If you want to use CONSUL logo you can [download the guidelines](https://raw.githubusercontent.com/consul/consul/master/public/consul_brand.zip) which contains a use guide and different versions and sizes of the logo. \ No newline at end of file diff --git a/README_ES.md b/README_ES.md index 155ab957f..b22312e29 100644 --- a/README_ES.md +++ b/README_ES.md @@ -23,14 +23,9 @@ Este es el repositorio de código abierto de la Aplicación de Participación Ci 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 [características](http://www.decide.es/es/) o 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). Para conocer el estado actual de las próximas caracteristicas, vaya a [Roadmap](https://github.com/consul/consul/projects/6) -## Tecnología - -El backend de esta aplicación se desarrolla con el lenguaje de programación [Ruby](https://www.ruby-lang.org/) sobre el *framework* [Ruby on Rails](http://rubyonrails.org/). -Las herramientas utilizadas para el frontend no están cerradas aún. Los estilos de la página usan [SCSS](http://sass-lang.com/) sobre [Foundation](http://foundation.zurb.com/) - ## Configuración para desarrollo y tests -**NOTA**: para unas instrucciones más detalladas consulta la [documentación](https://github.com/consul/consul/tree/master/doc/es/dev_test_setup.md) +**NOTA**: para unas instrucciones más detalladas consulta la [documentación](https://github.com/consul/docs/tree/master/es/getting_started/prerequisites) Prerequisitos: tener instalado git, Ruby 2.3.2, la gema `bundler` y PostgreSQL (9.4 o superior). @@ -41,7 +36,8 @@ cd consul bundle install cp config/database.yml.example config/database.yml cp config/secrets.yml.example config/secrets.yml -bin/rake db:setup +bin/rake db:create +bin/rake db:migrate bin/rake db:dev_seed RAILS_ENV=test rake db:setup ``` @@ -60,20 +56,6 @@ Para ejecutar los tests: bin/rspec ``` -Si añades código SCSS puedes revisarlo con: - -``` -scss-lint -``` - -Para mantener el nivel de accesibilidad, si añades colores nuevos utiliza un [Comprobador de contraste de color](http://webaim.org/resources/contrastchecker/) (WCAG AA es obligatorio, WCAG AAA es recomendable) - -Si trabajas en código coffeescript puedes revisarlo con [coffeelint](http://www.coffeelint.org/) (instalalo con `npm install -g coffeelint`) : - -``` -coffeelint . -``` - Puedes usar el usuario administrador por defecto del fichero seeds: **user:** admin@consul.dev @@ -84,15 +66,9 @@ Pero para ciertas acciones, como apoyar, necesitarás un usuario verificado, el **user:** verified@consul.dev **pass:** 12345678 -### Customización +## Documentación -Ver fichero [CUSTOMIZE_ES.md](CUSTOMIZE_ES.md) - -### OAuth - -Para probar los servicios de autenticación mediante proveedores externos OAuth — en este momento Twitter, Facebook y Google —, necesitas crear una "aplicación" en cada una de las plataformas soportadas y configurar la *key* y el *secret* proporcionados en tu *secrets.yml* - -En el caso de Google, comprueba que las APIs *Contacts API* y *Google+ API* están habilitadas para la aplicación. +Por favor visita la documentación que está siendo completada en https://consul_docs.gitbooks.io/docs/content/ para conocer más sobre este proyecto, como comenzar tu propio fork, instalarlo, customizarlo y usarlo como administrador/mantenedor. Puedes colaborar en ella en https://github.com/consul/docs ## Licencia @@ -101,7 +77,3 @@ El código de este proyecto está publicado bajo la licencia AFFERO GPL v3 (ver ## Contribuciones Ver fichero [CONTRIBUTING_ES.md](CONTRIBUTING_ES.md) - -## Guía de estilo - -Si quieres usar el logo de CONSUL puedes [descargar la guía de estilo](https://raw.githubusercontent.com/consul/consul/master/public/consul_brand.zip) que contiene una guía de uso y diferentes versiones y tamaños del logo. \ No newline at end of file diff --git a/app/assets/javascripts/comments.js.coffee b/app/assets/javascripts/comments.js.coffee index fefe85544..94845ca78 100644 --- a/app/assets/javascripts/comments.js.coffee +++ b/app/assets/javascripts/comments.js.coffee @@ -5,6 +5,8 @@ App.Comments = this.update_comments_count() add_reply: (parent_id, response_html) -> + if $("##{parent_id} .comment-children").length == 0 + $("##{parent_id}").append("
  • ") $("##{parent_id} .comment-children:first").prepend($(response_html)) this.update_comments_count() diff --git a/app/assets/stylesheets/datepicker_overrides.scss b/app/assets/stylesheets/datepicker_overrides.scss index d4c07802e..79414ad99 100644 --- a/app/assets/stylesheets/datepicker_overrides.scss +++ b/app/assets/stylesheets/datepicker_overrides.scss @@ -32,22 +32,30 @@ padding: 0; z-index: 4 !important; - .ui-datepicker-prev { - left: 12px; - } - - .ui-datepicker-next { - right: 12px; - } - .ui-datepicker-prev, .ui-datepicker-next { color: #fff; cursor: pointer; + font-family: "icons" !important; + font-size: rem-calc(24); font-weight: normal; - font-size: $small-font-size; + height: rem-calc(30); line-height: $line-height; - top: 0; + position: absolute; + top: 4px; + width: rem-calc(30); + + &:hover { + text-decoration: none; + } + } + + .ui-datepicker-prev::after { + content: '\62'; + } + + .ui-datepicker-next::after { + content: '\63'; } table { diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss index cf07f35ca..7e41026f1 100644 --- a/app/assets/stylesheets/layout.scss +++ b/app/assets/stylesheets/layout.scss @@ -205,7 +205,7 @@ a { .menu.simple { border-bottom: 1px solid $border; - margin: $line-height 0; + margin-bottom: $line-height; li { padding-bottom: rem-calc(7); diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index 3c37e9657..8c6fc5415 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -395,8 +395,8 @@ } } - &.tags, - &.geozone { + .tags, + .geozone { li { margin-bottom: 0; @@ -478,6 +478,7 @@ .tags { display: block; + margin-bottom: 0; a { margin-right: rem-calc(6); @@ -610,6 +611,14 @@ } } +.show-actions-menu { + + [class^="icon-"] { + display: inline-block; + vertical-align: middle; + } +} + // 04. List participation // ---------------------- @@ -896,9 +905,14 @@ } .help-header { + background: #fafafa; + border-bottom: 1px solid #eee; + padding-bottom: $line-height / 2; + padding-top: $line-height; h1 { font-size: rem-calc(24); + text-transform: uppercase; } } diff --git a/app/controllers/communities_controller.rb b/app/controllers/communities_controller.rb index ff74f208b..f6f1e4816 100644 --- a/app/controllers/communities_controller.rb +++ b/app/controllers/communities_controller.rb @@ -7,7 +7,7 @@ class CommunitiesController < ApplicationController skip_authorization_check def show - redirect_to root_path unless Setting['feature.community'].present? + redirect_to root_path if Setting['feature.community'].blank? end private diff --git a/app/controllers/documents_controller.rb b/app/controllers/documents_controller.rb index ceb7d191f..8f085e27f 100644 --- a/app/controllers/documents_controller.rb +++ b/app/controllers/documents_controller.rb @@ -1,8 +1,8 @@ class DocumentsController < ApplicationController before_action :authenticate_user! - before_filter :find_documentable, except: :destroy - before_filter :prepare_new_document, only: [:new, :new_nested] - before_filter :prepare_document_for_creation, only: :create + before_action :find_documentable, except: :destroy + before_action :prepare_new_document, only: [:new, :new_nested] + before_action :prepare_document_for_creation, only: :create load_and_authorize_resource except: :upload skip_authorization_check only: :upload @@ -48,6 +48,7 @@ class DocumentsController < ApplicationController def destroy_upload @document = Document.new(cached_attachment: params[:path]) @document.set_attachment_from_cached_attachment + @document.cached_attachment = nil @document.documentable = @documentable if @document.attachment.destroy diff --git a/app/controllers/officing/final_recounts_controller.rb b/app/controllers/officing/final_recounts_controller.rb deleted file mode 100644 index 3efd6a682..000000000 --- a/app/controllers/officing/final_recounts_controller.rb +++ /dev/null @@ -1,49 +0,0 @@ -class Officing::FinalRecountsController < Officing::BaseController - before_action :load_poll - before_action :load_officer_assignment, only: :create - - def new - @officer_assignments = ::Poll::OfficerAssignment. - includes(:final_recounts, booth_assignment: [:booth]). - joins(:booth_assignment). - final. - where(id: current_user.poll_officer.officer_assignment_ids). - where("poll_booth_assignments.poll_id = ?", @poll.id). - order(date: :asc) - - @final_recounts = @officer_assignments.select {|oa| oa.final_recounts.any?}.map(&:final_recounts).flatten - end - - def create - @final_recount = ::Poll::FinalRecount.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id, - date: final_recount_params[:date]) - @final_recount.officer_assignment_id = @officer_assignment.id - @final_recount.count = final_recount_params[:count] - - if @final_recount.save - msg = { notice: t("officing.final_recounts.flash.create") } - else - msg = { alert: t("officing.final_recounts.flash.error_create") } - end - redirect_to new_officing_poll_final_recount_path(@poll), msg - end - - private - - def load_poll - @poll = Poll.expired.find(params[:poll_id]) - end - - def load_officer_assignment - @officer_assignment = current_user.poll_officer. - officer_assignments.final.find_by(id: final_recount_params[:officer_assignment_id]) - if @officer_assignment.blank? - redirect_to new_officing_poll_final_recount_path(@poll), alert: t("officing.final_recounts.flash.error_create") - end - end - - def final_recount_params - params.permit(:officer_assignment_id, :count, :date) - end - -end diff --git a/app/controllers/officing/polls_controller.rb b/app/controllers/officing/polls_controller.rb index e122284ec..46bcf9f37 100644 --- a/app/controllers/officing/polls_controller.rb +++ b/app/controllers/officing/polls_controller.rb @@ -6,10 +6,11 @@ class Officing::PollsController < Officing::BaseController end def final - @polls = current_user.poll_officer? ? current_user.poll_officer.final_days_assigned_polls : [] - return unless current_user.poll_officer? - - @polls = @polls.select {|poll| poll.ends_at > 1.week.ago && poll.expired?} + @polls = if current_user.poll_officer? + current_user.poll_officer.final_days_assigned_polls.select {|poll| poll.ends_at > 2.week.ago && poll.expired?} + else + [] + end end -end \ No newline at end of file +end diff --git a/app/controllers/officing/results_controller.rb b/app/controllers/officing/results_controller.rb index 3a921a0d9..65a6deac5 100644 --- a/app/controllers/officing/results_controller.rb +++ b/app/controllers/officing/results_controller.rb @@ -28,6 +28,7 @@ class Officing::ResultsController < Officing::BaseController where(date: index_params[:date]) @whites = ::Poll::WhiteResult.where(booth_assignment_id: @booth_assignment.id, date: index_params[:date]).sum(:amount) @nulls = ::Poll::NullResult.where(booth_assignment_id: @booth_assignment.id, date: index_params[:date]).sum(:amount) + @total = ::Poll::TotalResult.where(booth_assignment_id: @booth_assignment.id, date: index_params[:date]).sum(:amount) end end @@ -70,6 +71,7 @@ class Officing::ResultsController < Officing::BaseController build_white_results build_null_results + build_total_results end def build_white_results @@ -96,6 +98,18 @@ class Officing::ResultsController < Officing::BaseController end end + def build_total_results + if results_params[:total].present? + total_result = ::Poll::TotalResult.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id, + date: results_params[:date]) + total_result.officer_assignment_id = @officer_assignment.id + total_result.amount = results_params[:total].to_i + total_result.author = current_user + total_result.origin = 'booth' + @results << total_result + end + end + def go_back_to_new(alert = nil) params[:d] = results_params[:date] params[:oa] = results_params[:officer_assignment_id] @@ -132,7 +146,7 @@ class Officing::ResultsController < Officing::BaseController end def results_params - params.permit(:officer_assignment_id, :date, :questions, :whites, :nulls) + params.permit(:officer_assignment_id, :date, :questions, :whites, :nulls, :total) end def index_params diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index cedc4e8ef..06e170ee2 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -78,7 +78,7 @@ class ProposalsController < ApplicationController def proposal_params params.require(:proposal).permit(:title, :question, :summary, :description, :external_url, :video_url, :responsible_name, :tag_list, :terms_of_service, :geozone_id, - documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id] ) + documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id]) end def retired_params diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb index d56c658bd..f9c2e8c69 100644 --- a/app/helpers/admin_helper.rb +++ b/app/helpers/admin_helper.rb @@ -36,6 +36,10 @@ module AdminHelper ["banners"].include? controller_name end + def menu_customization? + ["pages", "images", "content_blocks"].include? controller_name + end + def official_level_options options = [["", 0]] (1..5).each do |i| diff --git a/app/helpers/communities_helper.rb b/app/helpers/communities_helper.rb index bb770a948..22bc76617 100644 --- a/app/helpers/communities_helper.rb +++ b/app/helpers/communities_helper.rb @@ -12,7 +12,7 @@ module CommunitiesHelper community.from_proposal? ? t("community.show.description.proposal") : t("community.show.description.investment") end - def is_author?(community, participant) + def author?(community, participant) if community.from_proposal? community.proposal.author_id == participant.id else diff --git a/app/helpers/documentables_helper.rb b/app/helpers/documentables_helper.rb index 4fd737908..edbf88131 100644 --- a/app/helpers/documentables_helper.rb +++ b/app/helpers/documentables_helper.rb @@ -9,7 +9,7 @@ module DocumentablesHelper end def max_file_size(documentable) - bytesToMeg(documentable.class.max_file_size) + bytes_to_mega(documentable.class.max_file_size) end def accepted_content_types(documentable) @@ -18,8 +18,8 @@ module DocumentablesHelper def accepted_content_types_extensions(documentable_class) documentable_class.accepted_content_types - .collect{ |content_type| ".#{content_type.split("/").last}" } - .join(",") + .collect{ |content_type| ".#{content_type.split('/').last}" } + .join(",") end def humanized_accepted_content_types(documentable) @@ -38,4 +38,4 @@ module DocumentablesHelper documentable.documents.count >= documentable.class.max_documents_allowed end -end \ No newline at end of file +end diff --git a/app/helpers/documents_helper.rb b/app/helpers/documents_helper.rb index 17d70068b..72ebbf021 100644 --- a/app/helpers/documents_helper.rb +++ b/app/helpers/documents_helper.rb @@ -8,7 +8,7 @@ module DocumentsHelper document.errors[:attachment].join(', ') if document.errors.key?(:attachment) end - def bytesToMeg(bytes) + def bytes_to_mega(bytes) bytes / Numeric::MEGABYTE end @@ -80,10 +80,10 @@ module DocumentsHelper def document_direct_upload_url(document) upload_documents_url( - documentable_type: document.documentable_type, - documentable_id: document.documentable_id, - format: :js - ) + documentable_type: document.documentable_type, + documentable_id: document.documentable_id, + format: :js + ) end end diff --git a/app/helpers/embed_videos_helper.rb b/app/helpers/embed_videos_helper.rb index 1034a7a59..f1750bf8b 100644 --- a/app/helpers/embed_videos_helper.rb +++ b/app/helpers/embed_videos_helper.rb @@ -1,5 +1,8 @@ module EmbedVideosHelper + VIMEO_REGEX = /vimeo.*(staffpicks\/|channels\/|videos\/|video\/|\/)([^#\&\?]*).*/ + YOUTUBE_REGEX = /youtu.*(be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/ + def embedded_video_code link = @proposal.video_url title = t('proposals.show.embed_video_title', proposal: @proposal.title) @@ -10,10 +13,10 @@ module EmbedVideosHelper end if server == "Vimeo" - reg_exp = /vimeo.*(staffpicks\/|channels\/|videos\/|video\/|\/)([^#\&\?]*).*/ + reg_exp = VIMEO_REGEX src = "https://player.vimeo.com/video/" elsif server == "YouTube" - reg_exp = /youtu.*(be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/ + reg_exp = YOUTUBE_REGEX src = "https://www.youtube.com/embed/" end @@ -28,4 +31,11 @@ module EmbedVideosHelper end end -end \ No newline at end of file + def valid_video_url? + return if video_url.blank? + return if video_url.match(VIMEO_REGEX) + return if video_url.match(YOUTUBE_REGEX) + errors.add(:video_url, :invalid) + end + +end diff --git a/app/helpers/proposals_helper.rb b/app/helpers/proposals_helper.rb index 37425d573..d40f7950c 100644 --- a/app/helpers/proposals_helper.rb +++ b/app/helpers/proposals_helper.rb @@ -32,4 +32,16 @@ module ProposalsHelper Proposal::RETIRE_OPTIONS.collect { |option| [ t("proposals.retire_options.#{option}"), option ] } end + def can_create_document?(document, proposal) + can?(:create, document) && proposal.documents.size < Proposal.max_documents_allowed + end + + def author_of_proposal?(proposal) + author_of?(proposal, current_user) + end + + def current_editable?(proposal) + current_user && proposal.editable_by?(current_user) + end + end \ No newline at end of file diff --git a/app/models/community.rb b/app/models/community.rb index 3fa1cebaa..7d7073412 100644 --- a/app/models/community.rb +++ b/app/models/community.rb @@ -11,7 +11,7 @@ class Community < ActiveRecord::Base end def from_proposal? - self.proposal.present? + proposal.present? end private diff --git a/app/models/concerns/documentable.rb b/app/models/concerns/documentable.rb index 4aeaf6eab..729a0b0f8 100644 --- a/app/models/concerns/documentable.rb +++ b/app/models/concerns/documentable.rb @@ -10,7 +10,7 @@ module Documentable private - def documentable(options= {}) + def documentable(options = {}) @max_documents_allowed = options[:max_documents_allowed] @max_file_size = options[:max_file_size] @accepted_content_types = options[:accepted_content_types] diff --git a/app/models/document.rb b/app/models/document.rb index 7fd82ea33..3556d4c0a 100644 --- a/app/models/document.rb +++ b/app/models/document.rb @@ -40,7 +40,7 @@ class Document < ActiveRecord::Base attachment.instance.prefix(attachment, style) end - def prefix(attachment, style) + def prefix(attachment, _style) if !attachment.instance.persisted? "cached_attachments/user/#{attachment.instance.user_id}" else @@ -75,7 +75,7 @@ class Document < ActiveRecord::Base end def remove_cached_document - File.delete(cached_attachment) if File.exists?(cached_attachment) + File.delete(cached_attachment) if File.exist?(cached_attachment) end end diff --git a/app/models/poll.rb b/app/models/poll.rb index 4ba313963..3873ac5e0 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -4,6 +4,7 @@ class Poll < ActiveRecord::Base has_many :partial_results, through: :booth_assignments has_many :white_results, through: :booth_assignments has_many :null_results, through: :booth_assignments + has_many :total_results, through: :booth_assignments has_many :voters has_many :officer_assignments, through: :booth_assignments has_many :officers, through: :officer_assignments diff --git a/app/models/poll/booth.rb b/app/models/poll/booth.rb index 0aca6eecb..04f9d3dea 100644 --- a/app/models/poll/booth.rb +++ b/app/models/poll/booth.rb @@ -5,7 +5,7 @@ class Poll has_many :shifts validates :name, presence: true, uniqueness: true - + def self.search(terms) return Booth.none if terms.blank? Booth.where("name ILIKE ? OR location ILIKE ?", "%#{terms}%", "%#{terms}%") diff --git a/app/models/poll/booth_assignment.rb b/app/models/poll/booth_assignment.rb index 5ef9d687e..47cb01bfe 100644 --- a/app/models/poll/booth_assignment.rb +++ b/app/models/poll/booth_assignment.rb @@ -10,5 +10,6 @@ class Poll has_many :partial_results has_many :white_results has_many :null_results + has_many :total_results end end diff --git a/app/models/poll/question.rb b/app/models/poll/question.rb index 8e02dcfe2..a46f28a8c 100644 --- a/app/models/poll/question.rb +++ b/app/models/poll/question.rb @@ -20,6 +20,7 @@ class Poll::Question < ActiveRecord::Base validates :title, presence: true validates :author, presence: true + validates :poll_id, presence: true validates :title, length: { minimum: 4 } validates :description, length: { maximum: Poll::Question.description_max_length } diff --git a/app/models/poll/shift.rb b/app/models/poll/shift.rb index cc6a43425..d894df5a4 100644 --- a/app/models/poll/shift.rb +++ b/app/models/poll/shift.rb @@ -1,13 +1,13 @@ class Poll class Shift < ActiveRecord::Base - belongs_to :booth - belongs_to :officer + belongs_to :booth + belongs_to :officer validates :booth_id, presence: true validates :officer_id, presence: true validates :date, presence: true validates :date, uniqueness: { scope: [:officer_id, :booth_id] } - + before_create :persist_data after_create :create_officer_assignments @@ -20,10 +20,10 @@ class Poll end end - def persist_data + def persist_data self.officer_name = officer.name self.officer_email = officer.email end end - end \ No newline at end of file +end diff --git a/app/models/poll/total_result.rb b/app/models/poll/total_result.rb new file mode 100644 index 000000000..2df01929e --- /dev/null +++ b/app/models/poll/total_result.rb @@ -0,0 +1,23 @@ +class Poll::TotalResult < ActiveRecord::Base + + VALID_ORIGINS = %w{web booth} + + belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id' + belongs_to :booth_assignment + belongs_to :officer_assignment + + validates :author, presence: true + validates :origin, inclusion: {in: VALID_ORIGINS} + + scope :by_author, ->(author_id) { where(author_id: author_id) } + + before_save :update_logs + + def update_logs + if amount_changed? && amount_was.present? + self.amount_log += ":#{amount_was.to_s}" + self.officer_assignment_id_log += ":#{officer_assignment_id_was.to_s}" + self.author_id_log += ":#{author_id_was.to_s}" + end + end +end diff --git a/app/models/proposal.rb b/app/models/proposal.rb index 4ee4f851e..f9eeecc6f 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -15,6 +15,7 @@ class Proposal < ActiveRecord::Base max_file_size: 3.megabytes, accepted_content_types: [ "application/pdf" ] accepts_nested_attributes_for :documents, allow_destroy: true + include EmbedVideosHelper acts_as_votable acts_as_paranoid column: :hidden_at @@ -41,6 +42,8 @@ class Proposal < ActiveRecord::Base validates :terms_of_service, acceptance: { allow_nil: false }, on: :create + validate :valid_video_url? + before_validation :set_responsible_name before_save :calculate_hot_score, :calculate_confidence_score diff --git a/app/models/topic.rb b/app/models/topic.rb index 34abed0e3..e0a73d58b 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -13,6 +13,6 @@ class Topic < ActiveRecord::Base scope :sort_by_newest, -> { order(created_at: :desc) } scope :sort_by_oldest, -> { order(created_at: :asc) } - scope :sort_by_most_commented, -> { reorder(comments_count: :desc) } + scope :sort_by_most_commented, -> { reorder(comments_count: :desc) } end diff --git a/app/models/user.rb b/app/models/user.rb index ef6ab7832..006d1a09e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -57,13 +57,13 @@ class User < ActiveRecord::Base scope :officials, -> { where("official_level > 0") } scope :newsletter, -> { where(newsletter: true) } scope :for_render, -> { includes(:organization) } - scope :by_document, -> (document_type, document_number) { where(document_type: document_type, document_number: document_number) } + scope :by_document, ->(document_type, document_number) { where(document_type: document_type, document_number: document_number) } scope :email_digest, -> { where(email_digest: true) } scope :active, -> { where(erased_at: nil) } scope :erased, -> { where.not(erased_at: nil) } scope :public_for_api, -> { all } - scope :by_comments, -> (query, topics_ids) { joins(:comments).where(query, topics_ids).uniq } - scope :by_authors, -> (author_ids) { where("users.id IN (?)", author_ids) } + scope :by_comments, ->(query, topics_ids) { joins(:comments).where(query, topics_ids).uniq } + scope :by_authors, ->(author_ids) { where("users.id IN (?)", author_ids) } before_validation :clean_document_number diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index e629f5807..11d58adc8 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -60,12 +60,12 @@ <%= t("admin.menu.title_polls") %> -