diff --git a/Gemfile b/Gemfile index f1b251db4..e381bc516 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.3' +gem 'rails', '4.2.4' # Use PostgreSQL gem 'pg' # Use SCSS for stylesheets @@ -21,6 +21,11 @@ gem 'turbolinks' gem 'devise' # Use ActiveModel has_secure_password # gem 'bcrypt', '~> 3.1.7' +gem 'omniauth' +gem 'omniauth-twitter' +gem 'omniauth-facebook' +gem 'omniauth-google-oauth2' + gem 'kaminari' gem 'acts_as_commentable_with_threading' gem 'acts-as-taggable-on' @@ -32,7 +37,7 @@ gem 'simple_captcha2', require: 'simple_captcha' gem 'ckeditor' gem 'cancancan' gem 'social-share-button' -gem 'initialjs-rails' +gem 'initialjs-rails', '0.2.0' gem 'unicorn' gem 'paranoia' @@ -58,6 +63,7 @@ group :development, :test do gem "capistrano-bundler", '1.1.4', require: false gem "capistrano-rails", '1.1.3', require: false gem "capistrano-rvm", require: false + gem "bullet" end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index db469b072..78a442608 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,36 +1,36 @@ GEM remote: https://rubygems.org/ specs: - actionmailer (4.2.3) - actionpack (= 4.2.3) - actionview (= 4.2.3) - activejob (= 4.2.3) + actionmailer (4.2.4) + actionpack (= 4.2.4) + actionview (= 4.2.4) + activejob (= 4.2.4) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.3) - actionview (= 4.2.3) - activesupport (= 4.2.3) + actionpack (4.2.4) + actionview (= 4.2.4) + activesupport (= 4.2.4) 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.3) - activesupport (= 4.2.3) + actionview (4.2.4) + activesupport (= 4.2.4) 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.3) - activesupport (= 4.2.3) + activejob (4.2.4) + activesupport (= 4.2.4) globalid (>= 0.3.0) - activemodel (4.2.3) - activesupport (= 4.2.3) + activemodel (4.2.4) + activesupport (= 4.2.4) builder (~> 3.1) - activerecord (4.2.3) - activemodel (= 4.2.3) - activesupport (= 4.2.3) + activerecord (4.2.4) + activemodel (= 4.2.4) + activesupport (= 4.2.4) arel (~> 6.0) - activesupport (4.2.3) + activesupport (4.2.4) i18n (~> 0.7) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) @@ -62,6 +62,9 @@ GEM debug_inspector (>= 0.0.1) browser (0.9.1) builder (3.2.2) + bullet (4.14.7) + activesupport (>= 3.0.0) + uniform_notifier (~> 1.9.0) byebug (6.0.2) cancancan (1.12.0) capistrano (3.4.0) @@ -133,6 +136,8 @@ GEM factory_girl_rails (4.5.0) factory_girl (~> 4.5.0) railties (>= 3.0.0) + faraday (0.9.1) + multipart-post (>= 1.2, < 3) foundation-rails (5.5.2.1) railties (>= 3.1.0) sass (>= 3.3.0, < 3.5) @@ -150,6 +155,7 @@ GEM activesupport (>= 4.1.0) groupdate (2.4.0) activesupport (>= 3) + hashie (3.4.2) highline (1.7.3) http-cookie (1.0.2) domain_name (~> 0.5) @@ -162,13 +168,14 @@ GEM i18n term-ansicolor (>= 1.3.2) terminal-table (>= 1.5.1) - initialjs-rails (0.1.0) + initialjs-rails (0.2.0) railties (>= 3.1, < 5.0) jquery-rails (4.0.4) rails-dom-testing (~> 1.0) railties (>= 4.2.0) thor (>= 0.14, < 2.0) json (1.8.3) + jwt (1.5.1) kaminari (0.16.3) actionpack (>= 3.0.0) activesupport (>= 3.0.0) @@ -181,7 +188,7 @@ GEM actionmailer (>= 3.2) letter_opener (~> 1.0) railties (>= 3.2) - loofah (2.0.2) + loofah (2.0.3) nokogiri (>= 1.5.9) mail (2.6.3) mime-types (>= 1.16, < 3) @@ -189,12 +196,38 @@ GEM mini_portile (0.6.2) minitest (5.8.0) multi_json (1.11.2) + multi_xml (0.5.5) + multipart-post (2.0.0) net-scp (1.2.1) net-ssh (>= 2.6.5) net-ssh (2.9.2) netrc (0.10.3) nokogiri (1.6.6.2) mini_portile (~> 0.6.0) + oauth (0.4.7) + oauth2 (1.0.0) + faraday (>= 0.8, < 0.10) + jwt (~> 1.0) + multi_json (~> 1.3) + multi_xml (~> 0.5) + rack (~> 1.2) + omniauth (1.2.2) + hashie (>= 1.2, < 4) + rack (~> 1.0) + omniauth-facebook (2.0.1) + omniauth-oauth2 (~> 1.2) + omniauth-google-oauth2 (0.2.6) + omniauth (> 1.0) + omniauth-oauth2 (~> 1.1) + omniauth-oauth (1.1.0) + oauth + omniauth (~> 1.0) + omniauth-oauth2 (1.3.1) + oauth2 (~> 1.0) + omniauth (~> 1.2) + omniauth-twitter (1.2.1) + json (~> 1.3) + omniauth-oauth (~> 1.1) orm_adapter (0.5.0) paranoia (2.1.3) activerecord (~> 4.0) @@ -209,28 +242,28 @@ GEM rack (1.6.4) rack-test (0.6.3) rack (>= 1.0) - rails (4.2.3) - actionmailer (= 4.2.3) - actionpack (= 4.2.3) - actionview (= 4.2.3) - activejob (= 4.2.3) - activemodel (= 4.2.3) - activerecord (= 4.2.3) - activesupport (= 4.2.3) + rails (4.2.4) + actionmailer (= 4.2.4) + actionpack (= 4.2.4) + actionview (= 4.2.4) + activejob (= 4.2.4) + activemodel (= 4.2.4) + activerecord (= 4.2.4) + activesupport (= 4.2.4) bundler (>= 1.3.0, < 2.0) - railties (= 4.2.3) + railties (= 4.2.4) sprockets-rails rails-deprecated_sanitizer (1.0.3) activesupport (>= 4.2.0.alpha) - rails-dom-testing (1.0.6) + rails-dom-testing (1.0.7) activesupport (>= 4.2.0.beta, < 5.0) nokogiri (~> 1.6.0) rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.2) loofah (~> 2.0) - railties (4.2.3) - actionpack (= 4.2.3) - activesupport (= 4.2.3) + railties (4.2.4) + actionpack (= 4.2.4) + activesupport (= 4.2.4) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) raindrops (0.15.0) @@ -283,7 +316,7 @@ GEM coffee-rails sass-rails spring (1.3.6) - sprockets (3.2.0) + sprockets (3.3.3) rack (~> 1.0) sprockets-rails (2.3.2) actionpack (>= 3.0) @@ -315,6 +348,7 @@ GEM kgio (~> 2.6) rack raindrops (~> 0.7) + uniform_notifier (1.9.0) user_agent_parser (2.2.0) uuidtools (2.1.5) warden (1.2.3) @@ -338,6 +372,7 @@ DEPENDENCIES acts_as_commentable_with_threading acts_as_votable ahoy_matey (~> 1.2.1) + bullet byebug cancancan capistrano (= 3.4.0) @@ -357,16 +392,20 @@ DEPENDENCIES fuubar groupdate i18n-tasks - initialjs-rails + initialjs-rails (= 0.2.0) jquery-rails kaminari launchy letter_opener_web (~> 1.3.0) + omniauth + omniauth-facebook + omniauth-google-oauth2 + omniauth-twitter paranoia pg poltergeist quiet_assets - rails (= 4.2.3) + rails (= 4.2.4) responders rspec-rails (~> 3.0) sass-rails (~> 5.0) diff --git a/README.md b/README.md index 6c8bbb453..a3433df9d 100644 --- a/README.md +++ b/README.md @@ -27,23 +27,29 @@ cd participacion bundle install cp config/database.yml.example config/database.yml cp config/secrets.yml.example config/secrets.yml -bundle exec bin/rake db:setup -RAILS_ENV=test bundle exec rake db:setup +bin/rake db:setup +RAILS_ENV=test bin/rake db:setup ``` Para ejecutar la aplicación en local: ``` -bundle exec bin/rails s +bin/rails s ``` -Prerequisitos para los tests: tener instalado PhantomJS >= 2.0 +Prerequisitos para los tests: tener instalado PhantomJS >= 2.0 Para ejecutar los tests: ``` -bundle exec bin/rspec +bin/rspec ``` +### 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. + ## Licencia El código de este proyecto está publicado bajo la licencia AFFERO GPL v3 (ver [LICENSE-AGPLv3.txt](LICENSE-AGPLv3.txt)) diff --git a/README_EN.md b/README_EN.md index 9ebc58731..a3dd63106 100644 --- a/README_EN.md +++ b/README_EN.md @@ -28,13 +28,13 @@ cd participacion bundle install cp config/database.yml.example config/database.yml cp config/secrets.yml.example config/secrets.yml -bundle exec bin/rake db:setup -RAILS_ENV=test bundle exec rake db:setup +bin/rake db:setup +RAILS_ENV=test bin/rake db:setup ``` Run the app locally: ``` -bundle exec bin/rails s +bin/rails s ``` Prerequisites for testing: install PhantomJS >= 2.0 @@ -42,7 +42,7 @@ Prerequisites for testing: install PhantomJS >= 2.0 Run the tests with: ``` -bundle exec bin/rspec +bin/rspec ``` ## Licence diff --git a/app/assets/fonts/icons.eot b/app/assets/fonts/icons.eot index 2c00f1f5b..a1cc83d43 100644 Binary files a/app/assets/fonts/icons.eot and b/app/assets/fonts/icons.eot differ diff --git a/app/assets/fonts/icons.svg b/app/assets/fonts/icons.svg index 2f04723b8..049938913 100644 --- a/app/assets/fonts/icons.svg +++ b/app/assets/fonts/icons.svg @@ -29,4 +29,5 @@ + diff --git a/app/assets/fonts/icons.ttf b/app/assets/fonts/icons.ttf index 808c75487..aa9c63faa 100644 Binary files a/app/assets/fonts/icons.ttf and b/app/assets/fonts/icons.ttf differ diff --git a/app/assets/fonts/icons.woff b/app/assets/fonts/icons.woff index cc9c32cdf..b17f63445 100644 Binary files a/app/assets/fonts/icons.woff and b/app/assets/fonts/icons.woff differ diff --git a/app/assets/images/logo_email_gobierno_abierto.png b/app/assets/images/logo_email_gobierno_abierto.png new file mode 100644 index 000000000..8fe100fce Binary files /dev/null and b/app/assets/images/logo_email_gobierno_abierto.png differ diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index 7e6096bc3..5afa088d1 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -140,7 +140,7 @@ body.admin { .delete { border-bottom: 1px dotted #CF2A0E; - color: #F04124; + color: $delete; font-size: rem-calc(12); &:hover, &:active, &:focus { @@ -151,16 +151,27 @@ body.admin { .verified { color: $check; + + a { + border-bottom: 1px dotted $check; + color: $check; + font-size: rem-calc(12); + } } -.verified a { - border-bottom: 1px dotted $check; - color: $check; +.archived { + color: $text-medium; font-size: rem-calc(12); } .rejected { - color: #F04124; + color: $delete; +} + +.date { + color: $text-medium; + font-size: rem-calc(12); + font-style: italic; } .level { diff --git a/app/assets/stylesheets/debates.scss b/app/assets/stylesheets/debates.scss index 66ea491af..641e7ccff 100644 --- a/app/assets/stylesheets/debates.scss +++ b/app/assets/stylesheets/debates.scss @@ -5,6 +5,7 @@ // 03. Show // 04. New // 05. Comments +// 06. Flags // // 01. Debates @@ -541,6 +542,10 @@ font-size: rem-calc(12); margin: rem-calc(6) 0; padding: rem-calc(6); + + .divider { + color: $text-light; + } } .comment-user { @@ -608,3 +613,17 @@ .faded { opacity: 0.4; } + +// 06. Flags +// - - - - - - - - - - - - - - - - - - - - - - - - - + +.flag-disable { + color: $text-medium; + line-height: rem-calc(24); + vertical-align: middle; +} + +.flag-active { + @extend .flag-disable; + color: $delete; +} diff --git a/app/assets/stylesheets/icons.scss b/app/assets/stylesheets/icons.scss index ac6bb9dab..6a014579c 100644 --- a/app/assets/stylesheets/icons.scss +++ b/app/assets/stylesheets/icons.scss @@ -103,3 +103,7 @@ .icon-x:before { content: "v"; } +.icon-flag:before { + content: "w"; +} + diff --git a/app/assets/stylesheets/participacion.scss b/app/assets/stylesheets/participacion.scss index 485dbfd60..e20a2cb36 100644 --- a/app/assets/stylesheets/participacion.scss +++ b/app/assets/stylesheets/participacion.scss @@ -135,6 +135,7 @@ h1, h2, h3, h4, h5, h6 { } .sub-nav dt, .sub-nav dd, .sub-nav li { + padding: rem-calc(3) 0; &.active { background: #008CBA; @@ -142,7 +143,7 @@ h1, h2, h3, h4, h5, h6 { color: white; cursor: default; font-weight: normal; - padding: 0.16667rem 0.88889rem; + padding: rem-calc(3) rem-calc(14); a:hover { color: #737373; @@ -150,6 +151,37 @@ h1, h2, h3, h4, h5, h6 { } } +.f-dropdown { + li a { + font-size: rem-calc(12); + + &:hover { + color: $link-hover; + } + } + + li:hover, .f-dropdown li:focus { + background: white; + } + + &.open { + outline: none; + } +} + +.margin { + margin-top: $line-height; + margin-bottom: $line-height; +} + +.margin-top { + margin-top: $line-height; +} + +.margin-bottom { + margin-bottom: $line-height; +} + // 04. Header // - - - - - - - - - - - - - - - - - - - - - - - - - @@ -494,9 +526,14 @@ footer { h2 { clear: both; - font-size: rem-calc(30); + font-size: rem-calc(18); font-weight: bold; - line-height: $line-height*2; + line-height: $line-height; + + @media (min-width: $small-breakpoint) { + font-size: rem-calc(30); + line-height: $line-height*2; + } } .back, .icon-angle-left { @@ -692,13 +729,13 @@ form { } } -img.admin-avatar, img.moderator-avatar { +img.avatar, img.admin-avatar, img.moderator-avatar { border-radius: rem-calc(1000); position: relative; } img.initialjs-avatar { - @extend .moderator-avatar; + @extend .avatar; } .author-deleted { diff --git a/app/assets/stylesheets/variables.scss b/app/assets/stylesheets/variables.scss index 4be7028e3..6240702d2 100644 --- a/app/assets/stylesheets/variables.scss +++ b/app/assets/stylesheets/variables.scss @@ -38,6 +38,7 @@ $votes-like-act: #5D9E7F; $votes-unlike: #EF8585; $votes-unlike-act: #BD6A6A; +$delete: #F04124; $check: #46DB91; // 03. Forms @@ -84,6 +85,7 @@ $comment-official: rgba(70,219,145,.3); // 06. Responsive // - - - - - - - - - - - - - - - - - - - - - - - - - +$small: em-calc(480); $small-breakpoint: em-calc(640); $medium-breakpoint: em-calc(1024); $large-breakpoint: em-calc(1440); diff --git a/app/controllers/admin/officials_controller.rb b/app/controllers/admin/officials_controller.rb index 023f0f7fc..f83aa1e18 100644 --- a/app/controllers/admin/officials_controller.rb +++ b/app/controllers/admin/officials_controller.rb @@ -1,11 +1,11 @@ class Admin::OfficialsController < Admin::BaseController def index - @officials = User.officials.page(params[:page]) + @officials = User.officials.page(params[:page]).for_render end def search - @users = User.with_email(params[:email]).page(params[:page]) + @users = User.with_email(params[:email]).page(params[:page]).for_render end def edit @@ -29,4 +29,4 @@ class Admin::OfficialsController < Admin::BaseController params.require(:user).permit(:official_position, :official_level) end -end \ No newline at end of file +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b879a4a8d..802dda3bc 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -13,6 +13,8 @@ class ApplicationController < ActionController::Base # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception + before_action :ensure_signup_complete + rescue_from CanCan::AccessDenied do |exception| redirect_to main_app.root_url, alert: exception.message end @@ -40,4 +42,13 @@ class ApplicationController < ActionController::Base def set_debate_votes(debates) @voted_values = current_user ? current_user.debate_votes(debates) : {} end + + def ensure_signup_complete + # Ensure we don't go into an infinite loop + return if action_name.in? %w(finish_signup do_finish_signup) + + if user_signed_in? && !current_user.email_provided? + redirect_to finish_signup_path + end + end end diff --git a/app/controllers/debates_controller.rb b/app/controllers/debates_controller.rb index f8e7b968a..cf6d14f65 100644 --- a/app/controllers/debates_controller.rb +++ b/app/controllers/debates_controller.rb @@ -5,13 +5,13 @@ class DebatesController < ApplicationController respond_to :html, :js def index - @debates = Debate.includes(:tags).includes(:inappropiate_flags).search(params).page(params[:page]) + @debates = Debate.search(params).page(params[:page]).for_render set_debate_votes(@debates) end def show set_debate_votes(@debate) - @comments = @debate.root_comments.with_hidden.includes(:inappropiate_flags).recent.page(params[:page]) + @comments = @debate.root_comments.recent.page(params[:page]).for_render end def new diff --git a/app/controllers/moderation/comments_controller.rb b/app/controllers/moderation/comments_controller.rb index 03667e286..8a4d3768e 100644 --- a/app/controllers/moderation/comments_controller.rb +++ b/app/controllers/moderation/comments_controller.rb @@ -19,8 +19,8 @@ class Moderation::CommentsController < Moderation::BaseController redirect_to request.query_parameters.merge(action: :index) end - def mark_as_reviewed - @comment.mark_as_reviewed + def archive + @comment.archive redirect_to request.query_parameters.merge(action: :index) end @@ -31,7 +31,7 @@ class Moderation::CommentsController < Moderation::BaseController end def set_valid_filters - @valid_filters = %w{all pending_review reviewed} + @valid_filters = %w{all pending archived} end def parse_filter diff --git a/app/controllers/moderation/debates_controller.rb b/app/controllers/moderation/debates_controller.rb index 22e4eac6b..3492ee423 100644 --- a/app/controllers/moderation/debates_controller.rb +++ b/app/controllers/moderation/debates_controller.rb @@ -19,8 +19,8 @@ class Moderation::DebatesController < Moderation::BaseController redirect_to request.query_parameters.merge(action: :index) end - def mark_as_reviewed - @debate.mark_as_reviewed + def archive + @debate.archive redirect_to request.query_parameters.merge(action: :index) end @@ -31,7 +31,7 @@ class Moderation::DebatesController < Moderation::BaseController end def set_valid_filters - @valid_filters = %w{all pending_review reviewed} + @valid_filters = %w{all pending archived} end def parse_filter diff --git a/app/controllers/organizations/registrations_controller.rb b/app/controllers/organizations/registrations_controller.rb index 8602ba4ba..630cc64e4 100644 --- a/app/controllers/organizations/registrations_controller.rb +++ b/app/controllers/organizations/registrations_controller.rb @@ -5,6 +5,9 @@ class Organizations::RegistrationsController < Devise::RegistrationsController end end + def success + end + def create build_resource(sign_up_params) if resource.valid_with_captcha? @@ -17,6 +20,11 @@ class Organizations::RegistrationsController < Devise::RegistrationsController end end + protected + def after_inactive_sign_up_path_for(resource) + organizations_sign_up_success_path + end + private def sign_up_params diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb new file mode 100644 index 000000000..8588ba243 --- /dev/null +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -0,0 +1,29 @@ +class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController + def self.provides_callback_for(provider) + class_eval %Q{ + def #{provider} + @user = User.find_for_oauth(env["omniauth.auth"], current_user) + + if @user.persisted? + sign_in_and_redirect @user, event: :authentication + set_flash_message(:notice, :success, kind: "#{provider}".capitalize) if is_navigational_format? + else + session["devise.#{provider}_data"] = env["omniauth.auth"] + redirect_to new_user_registration_url + end + end + } + end + + [:twitter, :facebook, :google_oauth2].each do |provider| + provides_callback_for provider + end + + def after_sign_in_path_for(resource) + if resource.email_provided? + super(resource) + else + finish_signup_path + end + end +end diff --git a/app/controllers/users/registrations_controller.rb b/app/controllers/users/registrations_controller.rb index 0ef0ba638..4ce5998c8 100644 --- a/app/controllers/users/registrations_controller.rb +++ b/app/controllers/users/registrations_controller.rb @@ -1,4 +1,5 @@ class Users::RegistrationsController < Devise::RegistrationsController + prepend_before_filter :authenticate_scope!, only: [:edit, :update, :destroy, :finish_signup, :do_finish_signup] def create build_resource(sign_up_params) @@ -9,6 +10,19 @@ class Users::RegistrationsController < Devise::RegistrationsController end end + def finish_signup + end + + def do_finish_signup + if current_user.update(sign_up_params) + current_user.skip_reconfirmation! + sign_in(current_user, bypass: true) + redirect_to root_url + else + render :finish_signup + end + end + private def sign_up_params diff --git a/app/models/ability.rb b/app/models/ability.rb index a29f09a60..c8ed63d22 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -53,14 +53,14 @@ class Ability can :hide, Comment, hidden_at: nil cannot :hide, Comment, user_id: user.id - can :mark_as_reviewed, Comment, reviewed_at: nil, hidden_at: nil - cannot :mark_as_reviewed, Comment, user_id: user.id + can :archive, Comment, archived_at: nil, hidden_at: nil + cannot :archive, Comment, user_id: user.id can :hide, Debate, hidden_at: nil cannot :hide, Debate, author_id: user.id - can :mark_as_reviewed, Debate, reviewed_at: nil, hidden_at: nil - cannot :mark_as_reviewed, Debate, author_id: user.id + can :archive, Debate, archived_at: nil, hidden_at: nil + cannot :archive, Debate, author_id: user.id can :hide, User cannot :hide, User, id: user.id diff --git a/app/models/comment.rb b/app/models/comment.rb index 824f1dbf0..bbfeca4f5 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -9,19 +9,20 @@ class Comment < ActiveRecord::Base validates :body, presence: true validates :user, presence: true - belongs_to :commentable, polymorphic: true + belongs_to :commentable, polymorphic: true, counter_cache: true belongs_to :user, -> { with_hidden } has_many :inappropiate_flags, :as => :flaggable - default_scope { includes(:user) } scope :recent, -> { order(id: :desc) } scope :sorted_for_moderation, -> { order(inappropiate_flags_count: :desc, updated_at: :desc) } - scope :pending_review, -> { where(reviewed_at: nil, hidden_at: nil) } - scope :reviewed, -> { where("reviewed_at IS NOT NULL AND hidden_at IS NULL") } + scope :pending, -> { where(archived_at: nil, hidden_at: nil) } + scope :archived, -> { where("archived_at IS NOT NULL AND hidden_at IS NULL") } scope :flagged_as_inappropiate, -> { where("inappropiate_flags_count > 0") } + scope :for_render, -> { with_hidden.includes(user: :organization) } + def self.build(commentable, user, body) new commentable: commentable, user_id: user.id, @@ -49,15 +50,23 @@ class Comment < ActiveRecord::Base end def total_votes - votes_for.size + cached_votes_total + end + + def total_likes + cached_votes_up + end + + def total_dislikes + cached_votes_down end def not_visible? hidden? || user.hidden? end - def reviewed? - reviewed_at.present? + def archived? + archived_at.present? end def as_administrator? @@ -68,8 +77,8 @@ class Comment < ActiveRecord::Base moderator_id.present? end - def mark_as_reviewed - update(reviewed_at: Time.now) + def archive + update(archived_at: Time.now) end # TODO: faking counter cache since there is a bug with acts_as_nested_set :counter_cache @@ -80,4 +89,8 @@ class Comment < ActiveRecord::Base children.count end + def after_hide + commentable_type.constantize.reset_counters(commentable_id, :comment_threads) + end + end diff --git a/app/models/debate.rb b/app/models/debate.rb index c16048f70..15590fc60 100644 --- a/app/models/debate.rb +++ b/app/models/debate.rb @@ -24,9 +24,10 @@ class Debate < ActiveRecord::Base before_validation :sanitize_tag_list scope :sorted_for_moderation, -> { order(inappropiate_flags_count: :desc, updated_at: :desc) } - scope :pending_review, -> { where(reviewed_at: nil, hidden_at: nil) } - scope :reviewed, -> { where("reviewed_at IS NOT NULL AND hidden_at IS NULL") } + scope :pending, -> { where(archived_at: nil, hidden_at: nil) } + scope :archived, -> { where("archived_at IS NOT NULL AND hidden_at IS NULL") } scope :flagged_as_inappropiate, -> { where("inappropiate_flags_count > 0") } + scope :for_render, -> { includes(:tags) } # Ahoy setup visitable # Ahoy will automatically assign visit_id on create @@ -40,15 +41,15 @@ class Debate < ActiveRecord::Base end def likes - get_likes.size + cached_votes_up end def dislikes - get_dislikes.size + cached_votes_down end def total_votes - votes_for.size + cached_votes_total end def editable? @@ -74,12 +75,12 @@ class Debate < ActiveRecord::Base count < 0 ? 0 : count end - def reviewed? - reviewed_at.present? + def archived? + archived_at.present? end - def mark_as_reviewed - update(reviewed_at: Time.now) + def archive + update(archived_at: Time.now) end protected diff --git a/app/models/identity.rb b/app/models/identity.rb new file mode 100644 index 000000000..3ba19e3fa --- /dev/null +++ b/app/models/identity.rb @@ -0,0 +1,17 @@ +class Identity < ActiveRecord::Base + belongs_to :user + + validates :provider, presence: true + validates :uid, presence: true, uniqueness: { scope: :provider } + + def self.find_for_oauth(auth) + where(uid: auth.uid, provider: auth.provider).first_or_create + end + + def update_user(new_user) + return unless user != new_user + + self.user = new_user + save! + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 179686725..355a1c326 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,8 +1,12 @@ class User < ActiveRecord::Base include ActsAsParanoidAliases + + OMNIAUTH_EMAIL_PREFIX = 'omniauth@participacion' + OMNIAUTH_EMAIL_REGEX = /\A#{OMNIAUTH_EMAIL_PREFIX}/ + apply_simple_captcha devise :database_authenticatable, :registerable, :confirmable, - :recoverable, :rememberable, :trackable, :validatable + :recoverable, :rememberable, :trackable, :validatable, :omniauthable acts_as_voter acts_as_paranoid column: :hidden_at @@ -11,19 +15,58 @@ class User < ActiveRecord::Base has_one :moderator has_one :organization has_many :inappropiate_flags + has_many :identities, dependent: :destroy - validates :username, presence: true, unless: :organization? + validates :username, presence: true, unless: :organization? validates :official_level, inclusion: {in: 0..5} + validates_format_of :email, without: OMNIAUTH_EMAIL_REGEX, on: :update validates_associated :organization, message: false accepts_nested_attributes_for :organization - default_scope { includes(:organization) } scope :administrators, -> { joins(:administrators) } scope :moderators, -> { joins(:moderator) } scope :organizations, -> { joins(:organization) } scope :officials, -> { where("official_level > 0") } + scope :for_render, -> { includes(:organization) } + + def self.find_for_oauth(auth, signed_in_resource = nil) + # Get the identity and user if they exist + identity = Identity.find_for_oauth(auth) + + # If a signed_in_resource is provided it always overrides the existing user + # to prevent the identity being locked with accidentally created accounts. + # Note that this may leave zombie accounts (with no associated identity) which + # can be cleaned up at a later date. + user = signed_in_resource ? signed_in_resource : identity.user + user ||= first_or_create_for_oauth(auth) + + # Associate the identity with the user if needed + identity.update_user(user) + user + end + + # Get the existing user by email if the provider gives us a verified email. + # If no verified email was provided we assign a temporary email and ask the + # user to verify it on the next step via RegistrationsController.finish_signup + def self.first_or_create_for_oauth(auth) + email = auth.info.email if auth.info.verified || auth.info.verified_email + user = User.where(email: email).first if email + + # Create the user if it's a new registration + if user.nil? + user = User.new( + username: auth.info.nickname || auth.extra.raw_info.name.parameterize('-') || auth.uid, + email: email ? email : "#{OMNIAUTH_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com", + password: Devise.friendly_token[0,20] + ) + user.skip_confirmation! + user.save! + end + + user + end def name organization? ? organization.name : username @@ -71,4 +114,8 @@ class User < ActiveRecord::Base moderator? ? self.moderator.destroy : create_moderator end + def email_provided? + !!(email && email !~ OMNIAUTH_EMAIL_REGEX) || + !!(unconfirmed_email && unconfirmed_email !~ OMNIAUTH_EMAIL_REGEX) + end end diff --git a/app/views/account/show.html.erb b/app/views/account/show.html.erb index d24343ea5..fa9ccdd04 100644 --- a/app/views/account/show.html.erb +++ b/app/views/account/show.html.erb @@ -26,7 +26,7 @@

<%= t("account.show.avatar")%>

- <%= avatar_image(@account, size: 100) %> + <%= avatar_image(@account, seed: @account.id, size: 100) %>

<%= t("account.show.notifications")%>

diff --git a/app/views/comments/_actions.html.erb b/app/views/comments/_actions.html.erb index 5454179f0..51a6743e0 100644 --- a/app/views/comments/_actions.html.erb +++ b/app/views/comments/_actions.html.erb @@ -1,12 +1,16 @@ + + <%= render 'comments/flag_as_inappropiate_actions', comment: comment %> + + <% if can? :hide, comment %> -  |  +  •  <%= link_to t("admin.actions.hide").capitalize, hide_moderation_comment_path(comment), method: :put, remote: true, data: { confirm: t('admin.actions.confirm') } %> <% end %> <% if can? :hide, comment.user %> -  |  +  •  <%= link_to t("admin.actions.hide_author").capitalize, hide_moderation_user_path(comment.user_id, debate_id: @debate.id), method: :put, data: { confirm: t('admin.actions.confirm') } %> <% end %> diff --git a/app/views/comments/_comment.html.erb b/app/views/comments/_comment.html.erb index ca7474ebd..5ffff4a85 100644 --- a/app/views/comments/_comment.html.erb +++ b/app/views/comments/_comment.html.erb @@ -14,7 +14,7 @@ <% if comment.user.organization? %> <%= image_tag("collective_avatar.png", size: 32, class: "avatar left") %> <% else %> - <%= avatar_image(comment.user, size: 32, class: "left") %> + <%= avatar_image(comment.user, seed: comment.user_id, size: 32, class: "left") %> <% end %> <% if comment.user.hidden? %> @@ -58,10 +58,6 @@ <% end %>  • <%= time_ago_in_words(comment.created_at) %> - - - <%= render 'comments/flag_as_inappropiate_actions', comment: comment %> -
<% if comment.as_administrator? %> @@ -81,11 +77,11 @@ <%= render 'comments/votes', comment: comment %> -

+

<%= t("debates.comment.responses", count: comment.children_count) %> <% if user_signed_in? %> -  |  +  |  <%= link_to(comment_link_text(comment), "", class: "js-add-comment-link", data: {'id': dom_id(comment)}) %> @@ -93,13 +89,13 @@ <%= render 'comments/form', {parent: comment, toggeable: true} %> <% end %> -

+
<% end %>
- <%= render comment.children.with_hidden.reorder('id DESC, lft') %> + <%= render comment.children.for_render.reorder('id DESC, lft') %>
diff --git a/app/views/comments/_flag_as_inappropiate_actions.html.erb b/app/views/comments/_flag_as_inappropiate_actions.html.erb index fad83d4d6..9fba8b5b2 100644 --- a/app/views/comments/_flag_as_inappropiate_actions.html.erb +++ b/app/views/comments/_flag_as_inappropiate_actions.html.erb @@ -1,6 +1,23 @@ <% if can? :flag_as_inappropiate, comment %> - <%= link_to t('shared.flag_as_inappropiate'), flag_as_inappropiate_comment_path(comment), method: :put, remote: true %> +  |  + + <% end %> + <% if can? :undo_flag_as_inappropiate, comment %> - <%= link_to t('shared.undo_flag_as_inappropiate'), undo_flag_as_inappropiate_comment_path(comment), method: :put, remote: true %> +  |  + + <% end %> diff --git a/app/views/comments/_votes.html.erb b/app/views/comments/_votes.html.erb index 73efa56ba..d7af65bff 100644 --- a/app/views/comments/_votes.html.erb +++ b/app/views/comments/_votes.html.erb @@ -1,5 +1,4 @@ - <%= t('debates.comment.votes', count: comment.total_votes) %>  |  @@ -8,7 +7,7 @@ method: "post", remote: true do %> <% end %> - <%= comment.get_likes.size %> + <%= comment.total_likes %> @@ -16,5 +15,5 @@ method: "post", remote: true do %> <% end %> - <%= comment.get_dislikes.size %> + <%= comment.total_dislikes %> diff --git a/app/views/debates/_debate.html.erb b/app/views/debates/_debate.html.erb index 4dd866df2..2d1e2deb4 100644 --- a/app/views/debates/_debate.html.erb +++ b/app/views/debates/_debate.html.erb @@ -9,7 +9,7 @@

<%= link_to debate.title, debate %>

  - <%= link_to t("debates.debate.comments", count: debate.comment_threads.count), debate_path(debate, anchor: "comments") %> + <%= link_to t("debates.debate.comments", count: debate.comments_count), debate_path(debate, anchor: "comments") %>

<%= link_to debate.description, debate %> diff --git a/app/views/debates/_flag_as_inappropiate_actions.html.erb b/app/views/debates/_flag_as_inappropiate_actions.html.erb index 8003600e0..6c3d34236 100644 --- a/app/views/debates/_flag_as_inappropiate_actions.html.erb +++ b/app/views/debates/_flag_as_inappropiate_actions.html.erb @@ -1,6 +1,21 @@ <% if can? :flag_as_inappropiate, debate %> - <%= link_to t('shared.flag_as_inappropiate'), flag_as_inappropiate_debate_path(debate), method: :put, remote: true %> + + <% end %> + <% if can? :undo_flag_as_inappropiate, debate %> - <%= link_to t('shared.undo_flag_as_inappropiate'), undo_flag_as_inappropiate_debate_path(debate), method: :put, remote: true %> + + <% end %> diff --git a/app/views/debates/show.html.erb b/app/views/debates/show.html.erb index 47ff9e34f..af25f28b1 100644 --- a/app/views/debates/show.html.erb +++ b/app/views/debates/show.html.erb @@ -13,7 +13,7 @@

<%= @debate.title %>

- <%= avatar_image(@debate.author, size: 32, class: 'author-photo') %> + <%= avatar_image(@debate.author, seed: @debate.author_id, size: 32, class: 'author-photo') %> <% if @debate.author.hidden? %> @@ -40,9 +40,9 @@ <%= l @debate.created_at.to_date %>  •    - <%= link_to t("debates.show.comments", count: @debate.comment_threads.count), "#comments" %> - - + <%= link_to t("debates.show.comments", count: @debate.comments_count), "#comments" %> +  •  + <%= render 'debates/flag_as_inappropiate_actions', debate: @debate %>
@@ -79,7 +79,7 @@

<%= t("debates.show.comments_title") %> - (<%= @debate.comment_threads.count %>) + (<%= @debate.comments_count %>)

<% if user_signed_in? %> <%= render 'comments/form', {parent: @debate, toggeable: false} %> diff --git a/app/views/devise/_omniauth_form.html.erb b/app/views/devise/_omniauth_form.html.erb new file mode 100644 index 000000000..fdd812b4f --- /dev/null +++ b/app/views/devise/_omniauth_form.html.erb @@ -0,0 +1,7 @@ +
+ +<%= link_to t("omniauth.twitter.sign_in"), user_omniauth_authorize_path(:twitter), class: 'button radius expand' %> +<%= link_to t("omniauth.facebook.sign_in"), user_omniauth_authorize_path(:facebook), class: 'button radius expand' %> +<%= link_to t("omniauth.google_oauth2.sign_in"), user_omniauth_authorize_path(:google_oauth2), class: 'button radius expand' %> + +
diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb index 1f504444d..c81e6fc74 100644 --- a/app/views/devise/mailer/confirmation_instructions.html.erb +++ b/app/views/devise/mailer/confirmation_instructions.html.erb @@ -1,5 +1,18 @@ -

<%= t("devise_views.mailer.confirmation_instructions.welcome") %> <%= @email %>

+ -

<%= t("devise_views.mailer.confirmation_instructions.text") %>

+

+ <%= t("devise_views.mailer.confirmation_instructions.title") %> +

-

<%= link_to t("devise_views.mailer.confirmation_instructions.confirm_link"), confirmation_url(@resource, confirmation_token: @token) %>

+

+ <%= t("devise_views.mailer.confirmation_instructions.welcome") %> <%= @email %> +

+ +

+ <%= t("devise_views.mailer.confirmation_instructions.text") %> +

+ +

+ <%= link_to t("devise_views.mailer.confirmation_instructions.confirm_link"), confirmation_url(@resource, confirmation_token: @token), style: "color: #2895F1; text-decoration:none;" %> +

+ diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb index 78923ce92..a67e77f08 100644 --- a/app/views/devise/mailer/reset_password_instructions.html.erb +++ b/app/views/devise/mailer/reset_password_instructions.html.erb @@ -1,8 +1,22 @@ -

<%= t("devise_views.mailer.reset_password_instructions.hello") %> <%= @resource.email %>

+ -

<%= t("devise_views.mailer.reset_password_instructions.text") %>

+

+ <%= t("devise_views.mailer.reset_password_instructions.title") %> +

-

<%= link_to t("devise_views.mailer.reset_password_instructions.change_link"), edit_password_url(@resource, reset_password_token: @token) %>

+

+ <%= t("devise_views.mailer.reset_password_instructions.hello") %> <%= @resource.email %> +

-

<%= t("devise_views.mailer.reset_password_instructions.ignore_text") %>

-

<%= t("devise_views.mailer.reset_password_instructions.info_text") %>

+

+ <%= t("devise_views.mailer.reset_password_instructions.text") %> +

+ +

+ <%= link_to t("devise_views.mailer.reset_password_instructions.change_link"), edit_password_url(@resource, reset_password_token: @token), style: "color: #2895F1; text-decoration:none;" %> +

+ +

+ <%= t("devise_views.mailer.reset_password_instructions.ignore_text") %> <%= t("devise_views.mailer.reset_password_instructions.info_text") %> +

+ diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb index 12f4d2b62..41ddc2f19 100644 --- a/app/views/devise/mailer/unlock_instructions.html.erb +++ b/app/views/devise/mailer/unlock_instructions.html.erb @@ -1,7 +1,22 @@ -

<%= t("devise_views.mailer.unlock_instructions.hello") %> <%= @resource.email %>

+ -

<%= t("devise_views.mailer.unlock_instructions.info_text") %>

+

+ <%= t("devise_views.mailer.unlock_instructions.title") %> +

-

<%= t("devise_views.mailer.unlock_instructions.instructions_text") %>

+

+ <%= t("devise_views.mailer.unlock_instructions.hello") %> <%= @resource.email %> +

-

<%= link_to t("devise_views.mailer.unlock_instructions.unlock_link"), unlock_url(@resource, unlock_token: @token) %>

+

+ <%= t("devise_views.mailer.unlock_instructions.info_text") %> +

+ +

+ <%= t("devise_views.mailer.unlock_instructions.instructions_text") %> +

+ +

+ <%= link_to t("devise_views.mailer.unlock_instructions.unlock_link"), unlock_url(@resource, unlock_token: @token), style: "color: #2895F1; text-decoration:none;" %> +

+ diff --git a/app/views/devise/menu/_login_items.html.erb b/app/views/devise/menu/_login_items.html.erb index 4959553f9..6cd27160d 100644 --- a/app/views/devise/menu/_login_items.html.erb +++ b/app/views/devise/menu/_login_items.html.erb @@ -7,11 +7,11 @@ <%= link_to(t("devise_views.menu.login_items.logout"), destroy_user_session_path, method: :delete) %> <% else %> -
  • - <%= link_to(t("devise_views.menu.login_items.login"), new_user_session_path) %> -
  • -
  • - <%= link_to(t("devise_views.menu.login_items.signup"), new_user_registration_path, class: "button radius small") %> -
  • +
  • + <%= link_to(t("devise_views.menu.login_items.login"), new_user_session_path) %> +
  • +
  • + <%= link_to(t("devise_views.menu.login_items.signup"), new_user_registration_path, class: "button radius small") %> +
  • <% end %> - \ No newline at end of file + diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb index 78a8b8b4c..1219c393d 100644 --- a/app/views/devise/passwords/new.html.erb +++ b/app/views/devise/passwords/new.html.erb @@ -19,4 +19,4 @@ <%= render "devise/shared/links" %>
    - \ No newline at end of file + diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index 391ef186c..ab0b22426 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -3,6 +3,8 @@

    <%= t("devise_views.sessions.new.title") %>

    + <%= render 'devise/omniauth_form' %> + <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
    @@ -28,4 +30,4 @@ <%= render "devise/shared/links" %>
    -
    \ No newline at end of file + diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb index 0fd80f429..7f8142144 100644 --- a/app/views/devise/shared/_links.html.erb +++ b/app/views/devise/shared/_links.html.erb @@ -25,7 +25,7 @@ <%= link_to t("devise_views.shared.links.new_unlock"), new_unlock_path(resource_name) %>
    <% end -%> - <%- if devise_mapping.omniauthable? %> + <%- if devise_mapping.omniauthable? && devise_mapping.name == 'user' %> <%- resource_class.omniauth_providers.each do |provider| %> <%= link_to t("devise_views.shared.links.signin_with_provider", provider: provider.to_s.titleize), omniauth_authorize_path(resource_name, provider) %>
    <% end -%> diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb index 991cf0ffa..91f31ab18 100644 --- a/app/views/layouts/mailer.html.erb +++ b/app/views/layouts/mailer.html.erb @@ -1,5 +1,42 @@ - - - <%= yield %> - + + + + Gobierno abierto + + + + + + + + + + + <%= yield %> + +
    + + + + +
    + + <%= image_tag('logo_email_gobierno_abierto.png', style: "border: 0; display: block; width: 100%;max-width: 370px") %> + +
    +
    + + + + + + + +
    +

    + Preguntas frecuentes  tec.gobiernoabierto@madrid.es

    +

    + © 2015 Ayuntamiento de Madrid

    +
    + diff --git a/app/views/mailer/comment.html.erb b/app/views/mailer/comment.html.erb index eb95c8031..959b8e0a0 100644 --- a/app/views/mailer/comment.html.erb +++ b/app/views/mailer/comment.html.erb @@ -1,6 +1,18 @@ -<%= t('mailers.comment.hi', recipient: @debate.author.name) %> + -
    <%= link_to @debate.title, debate_url(@debate) %>
    -
    <%= t('mailers.comment.new_comment_by', commenter: @comment.author.name) %>
    +

    + <%= t("mailers.comment.title") %> +

    -
    <%= @comment.body %>
    +

    + <%= t("mailers.comment.hi") %> <%= @debate.author.name %>, +

    + +

    + <%= t("mailers.comment.new_comment_by_html", commenter: @comment.author.name) %> <%= link_to @debate.title, debate_url(@debate), style: "color: #2895F1; text-decoration:none;" %> +

    + +

    + <%= @comment.body %> +

    + diff --git a/app/views/mailer/reply.html.erb b/app/views/mailer/reply.html.erb index 21cfeba1e..924234f02 100644 --- a/app/views/mailer/reply.html.erb +++ b/app/views/mailer/reply.html.erb @@ -1,6 +1,18 @@ -<%= t('mailers.reply.hi', recipient: @recipient.name) %> + -
    <%= link_to @debate.title, debate_url(@debate) %>
    -
    <%= t('mailers.reply.new_reply_by', commenter: @reply.author.name) %>
    +

    + <%= t("mailers.reply.title") %> +

    -
    <%= @reply.body %>
    +

    + <%= t("mailers.reply.hi") %> <%= @recipient.name %>, +

    + +

    + <%= t("mailers.reply.new_reply_by_html", commenter: @reply.author.name) %> <%= link_to @debate.title, debate_url(@debate), style: "color: #2895F1; text-decoration:none;" %> +

    + +

    + <%= @reply.body %> +

    + diff --git a/app/views/moderation/_menu.html.erb b/app/views/moderation/_menu.html.erb index 41e84287a..f64eeec3a 100644 --- a/app/views/moderation/_menu.html.erb +++ b/app/views/moderation/_menu.html.erb @@ -4,17 +4,17 @@ <%= t("moderation.dashboard.index.title") %> -
  • > +
  • > <%= link_to moderation_debates_path do %> - + <%= t('moderation.menu.flagged_debates') %> <% end %>
  • -
  • > +
  • > <%= link_to moderation_comments_path do %> - - <%= t('moderation.menu.flagged_comments') %> + + <%= t("moderation.menu.flagged_comments") %> <% end %>
  • diff --git a/app/views/moderation/comments/index.html.erb b/app/views/moderation/comments/index.html.erb index 0d89114f1..f4ce8ec67 100644 --- a/app/views/moderation/comments/index.html.erb +++ b/app/views/moderation/comments/index.html.erb @@ -1,45 +1,52 @@ -

    <%= t('moderation.comments.index.title') %>

    +

    <%= t("moderation.comments.index.title") %>

    + +

    <%= page_entries_info @comments %>

    - - - - - + + + + <% @comments.each do |comment| %> - - - - - - <% if can? :mark_as_reviewed, comment %> + + + + <% if can? :archive, comment %> <% end %> - <% if comment.reviewed? %> - <% end %> @@ -47,4 +54,3 @@
    <%= t('moderation.comments.index.headers.flags') %><%= t('moderation.comments.index.headers.updated_at') %><%= t('moderation.comments.index.headers.commentable_type') %><%= t('moderation.comments.index.headers.commentable') %><%= t('moderation.comments.index.headers.comment') %> + <%= t("moderation.comments.index.headers.commentable") %> |  + <%= t("moderation.comments.index.headers.commentable_type") %> |  + <%= t("moderation.comments.index.headers.updated_at") %> + <%= t("moderation.comments.index.headers.comment") %><%= t("moderation.comments.index.headers.flags") %><%= t("moderation.debates.index.headers.actions") %>
    <%= comment.inappropiate_flags_count %><%= l comment.updated_at.to_date %><%= comment.commentable_type.constantize.model_name.human %><%= link_to comment.commentable.title, comment.commentable %><%= comment.body %> - <%= link_to t('moderation.comments.index.hide'), hide_in_moderation_screen_moderation_comment_path(comment, request.query_parameters), method: :put %> + <%= link_to comment.commentable.title, comment.commentable %> +
    + <%= comment.commentable_type.constantize.model_name.human %> + <%= l comment.updated_at.to_date %>
    <%= comment.body %><%= comment.inappropiate_flags_count %> + <%= link_to t("moderation.comments.index.hide"), hide_in_moderation_screen_moderation_comment_path(comment, request.query_parameters), method: :put, class: "delete" %> + - <%= link_to t('moderation.comments.index.mark_as_reviewed'), mark_as_reviewed_moderation_comment_path(comment, request.query_parameters), method: :put %> + <%= link_to t("moderation.comments.index.archive"), archive_moderation_comment_path(comment, request.query_parameters), method: :put, class: "button radius tiny warning" %> - <%= t('moderation.comments.index.reviewed') %> + <% if comment.archived? %> + + <%= t("moderation.comments.index.archived") %>
    <%= paginate @comments %> - diff --git a/app/views/moderation/dashboard/index.html.erb b/app/views/moderation/dashboard/index.html.erb index 16eb4508f..df41493e6 100644 --- a/app/views/moderation/dashboard/index.html.erb +++ b/app/views/moderation/dashboard/index.html.erb @@ -1 +1,5 @@ -

    <%= t("moderation.dashboard.index.title") %>

    +

    <%= t("moderation.dashboard.index.title") %>

    + +

    Lorem ipsum moderator sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.

    + +

    Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

    diff --git a/app/views/moderation/debates/index.html.erb b/app/views/moderation/debates/index.html.erb index 611f68e16..ac11d2159 100644 --- a/app/views/moderation/debates/index.html.erb +++ b/app/views/moderation/debates/index.html.erb @@ -1,43 +1,51 @@ -

    <%= t('moderation.debates.index.title') %>

    +

    <%= t("moderation.debates.index.title") %>

    + +

    <%= page_entries_info @debates %>

    - - - - + + + <% @debates.each do |debate| %> - - - - - <% if can? :mark_as_reviewed, debate %> + + + <% if can? :archive, debate %> <% end %> - <% if debate.reviewed? %> - <% end %> @@ -45,4 +53,3 @@
    <%= t('moderation.debates.index.headers.flags') %><%= t('moderation.debates.index.headers.updated_at') %><%= t('moderation.debates.index.headers.title') %><%= t('moderation.debates.index.headers.description') %> + <%= t("moderation.debates.index.headers.title") %> |  + <%= t("moderation.debates.index.headers.updated_at") %> |  + <%= t("moderation.debates.index.headers.description") %> + <%= t("moderation.debates.index.headers.flags") %><%= t("moderation.debates.index.headers.actions") %>
    <%= debate.inappropiate_flags_count %><%= l debate.updated_at.to_date %><%= link_to debate.title, debate %><%= debate.description %> - <%= link_to t('moderation.debates.index.hide'), hide_in_moderation_screen_moderation_debate_path(debate, request.query_parameters), method: :put %> + <%= link_to debate.title, debate, target: "_blank" %> +
    + <%= l debate.updated_at.to_date %> +
    + <%= debate.description %>
    <%= debate.inappropiate_flags_count %> + <%= link_to t("moderation.debates.index.hide"), hide_in_moderation_screen_moderation_debate_path(debate, request.query_parameters), method: :put, class: "delete" %> + - <%= link_to t('moderation.debates.index.mark_as_reviewed'), mark_as_reviewed_moderation_debate_path(debate, request.query_parameters), method: :put %> + <%= link_to t("moderation.debates.index.archive"), archive_moderation_debate_path(debate, request.query_parameters), method: :put, class: "button radius tiny warning" %> - <%= t('moderation.debates.index.reviewed') %> + <% if debate.archived? %> + + <%= t("moderation.debates.index.archived") %>
    <%= paginate @debates %> - diff --git a/app/views/organizations/registrations/success.html.erb b/app/views/organizations/registrations/success.html.erb new file mode 100644 index 000000000..e246365f5 --- /dev/null +++ b/app/views/organizations/registrations/success.html.erb @@ -0,0 +1,15 @@ +
    +
    +
    +

    <%= t("devise_views.organizations.registrations.success.title") %>

    +

    <%= t("devise_views.organizations.registrations.success.thank_you") %>

    +

    <%= t("devise_views.organizations.registrations.success.instructions_1_html") %>

    +

    <%= t("devise_views.organizations.registrations.success.instructions_2_html") %>

    +

    <%= t("devise_views.organizations.registrations.success.instructions_3_html") %>

    +

    + <%= link_to t("devise_views.organizations.registrations.success.back_to_index"), + root_path, class: "button radius small margin-top" %> +

    +
    +
    +
    diff --git a/app/views/shared/_tags.html.erb b/app/views/shared/_tags.html.erb index 6a61bd4b4..2b599ec77 100644 --- a/app/views/shared/_tags.html.erb +++ b/app/views/shared/_tags.html.erb @@ -10,4 +10,4 @@ <%= link_to "#{debate.tags_count_out_of_limit(limit)}+", debate_path(debate) %> <% end %> -<% end %> +<% end %> \ No newline at end of file diff --git a/app/views/users/registrations/finish_signup.html.erb b/app/views/users/registrations/finish_signup.html.erb new file mode 100644 index 000000000..c57f01a8e --- /dev/null +++ b/app/views/users/registrations/finish_signup.html.erb @@ -0,0 +1,13 @@ +
    +
    +
    +

    <%= t('omniauth.finish_signup.title') %>

    + + <%= form_for current_user, as: :user, url: do_finish_signup_path, html: { role: 'form'} do |f| %> + <%= render 'shared/errors', resource: current_user %> + <%= f.email_field :email, placeholder: t("devise_views.users.registrations.new.email_label"), value: nil %> + <%= f.submit t("devise_views.users.registrations.new.submit"), class: 'button radius' %> + <% end %> +
    +
    +
    diff --git a/app/views/users/registrations/new.html.erb b/app/views/users/registrations/new.html.erb index 92344b76f..2ac5b7af6 100644 --- a/app/views/users/registrations/new.html.erb +++ b/app/views/users/registrations/new.html.erb @@ -2,6 +2,9 @@

    <%= t("devise_views.users.registrations.new.title") %>

    + + <%= render 'devise/omniauth_form' %> + <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= render 'shared/errors', resource: resource %> diff --git a/app/views/welcome/_featured_debate.html.erb b/app/views/welcome/_featured_debate.html.erb index 11cb3b733..7ad53608b 100644 --- a/app/views/welcome/_featured_debate.html.erb +++ b/app/views/welcome/_featured_debate.html.erb @@ -8,7 +8,7 @@

    <%= link_to featured_debate.title, featured_debate %>

      - <%= link_to t("debates.show.comments", count: featured_debate.comment_threads.count), debate_path(featured_debate, anchor: "comments") %> + <%= link_to t("debates.show.comments", count: featured_debate.comments_count), debate_path(featured_debate, anchor: "comments") %>

    <%= link_to featured_debate.description, featured_debate %> diff --git a/config/deploy/shared/secrets.yml.erb b/config/deploy/shared/secrets.yml.erb index a1cc29fb8..42a8c48a6 100644 --- a/config/deploy/shared/secrets.yml.erb +++ b/config/deploy/shared/secrets.yml.erb @@ -2,4 +2,10 @@ recaptcha_public_key: <%= ENV["MADRID_RECAPTCHA_PUBLIC_KEY"] %> recaptcha_private_key: <%= ENV["MADRID_RECAPTCHA_PRIVATE_KEY"] %> secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> - server_name: <%= fetch(:server_name) %> \ No newline at end of file + twitter_key: <%= ENV["TWITTER_KEY"] %> + twitter_secret: <%= ENV["TWITTER_SECRET"] %> + facebook_key: <%= ENV["FACEBOOK_KEY"] %> + facebook_secret: <%= ENV["FACEBOOK_SECRET"] %> + google_oauth2_key: <%= ENV["GOOGLE_KEY"] %> + google_oauth2_secret: <%= ENV["GOOGLE_SECRET"] %> + server_name: <%= fetch(:server_name) %> diff --git a/config/environments/development.rb b/config/environments/development.rb index acf67286d..566d4ebc5 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -16,6 +16,7 @@ Rails.application.configure do # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } + config.action_mailer.asset_host = "http://localhost:3000" # Deliver emails to a development mailbox at /letter_opener config.action_mailer.delivery_method = :letter_opener @@ -44,4 +45,13 @@ Rails.application.configure do # config.action_view.raise_on_missing_translations = true config.cache_store = :null_store + + config.after_initialize do + Bullet.enable = true + Bullet.bullet_logger = true + if ENV['BULLET'] + Bullet.rails_logger = true + Bullet.add_footer = true + end + end end diff --git a/config/environments/staging.rb b/config/environments/staging.rb index e84606f73..7a21a1df4 100644 --- a/config/environments/staging.rb +++ b/config/environments/staging.rb @@ -42,7 +42,7 @@ Rails.application.configure do # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - # config.force_ssl = true + config.force_ssl = true # Use the lowest log level to ensure availability of diagnostic information # when problems arise. diff --git a/config/environments/test.rb b/config/environments/test.rb index a76376fe6..cef568af6 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -45,4 +45,13 @@ Rails.application.configure do # config.action_view.raise_on_missing_translations = true config.cache_store = :null_store + + config.after_initialize do + Bullet.enable = true + Bullet.bullet_logger = true + if ENV['BULLET'] + Bullet.raise = true # raise an error if n+1 query occurs + end + end + end diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index f7cdfb292..6b1c860a9 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -239,6 +239,9 @@ Devise.setup do |config| # Add a new OmniAuth provider. Check the wiki for more information on setting # up on your models and hooks. # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo' + config.omniauth :twitter, Rails.application.secrets.twitter_key, Rails.application.secrets.twitter_secret + config.omniauth :facebook, Rails.application.secrets.facebook_key, Rails.application.secrets.facebook_secret + config.omniauth :google_oauth2, Rails.application.secrets.google_oauth2_key, Rails.application.secrets.google_oauth2_secret # ==> Warden configuration # If you want to use other strategies, that are not supported by Devise, or @@ -263,3 +266,7 @@ Devise.setup do |config| # so you need to do it manually. For the users scope, it would be: # config.omniauth_path_prefix = '/my_engine/users/auth' end + +Rails.application.config.to_prepare do + Devise::Mailer.layout "mailer" # email.haml or email.erb +end \ No newline at end of file diff --git a/config/locales/devise.es.yml b/config/locales/devise.es.yml index f39099f57..c2bc246e9 100644 --- a/config/locales/devise.es.yml +++ b/config/locales/devise.es.yml @@ -55,4 +55,4 @@ es: not_locked: "no estaba bloqueado." not_saved: one: "1 error impidió que este %{resource} fuera guardado:" - other: "%{count} errores impidieron que este %{resource} fuera guardado:" \ No newline at end of file + other: "%{count} errores impidieron que este %{resource} fuera guardado:" diff --git a/config/locales/devise_views.en.yml b/config/locales/devise_views.en.yml index e1b2a571d..08a303834 100644 --- a/config/locales/devise_views.en.yml +++ b/config/locales/devise_views.en.yml @@ -6,17 +6,20 @@ en: submit: "Resend confirmation instructions" mailer: confirmation_instructions: + title: "Welcome to open government" welcome: "Welcome" text: "You can confirm your account email through the link below:" confirm_link: "Confirm my account" reset_password_instructions: hello: "Hello" - text: "Someone has requested a link to change your password. You can do this through the link below." + title: Change your password + text: "Someone has requested to change your password. You can do this through the link below:" change_link: "Change my password" ignore_text: "If you didn't request this, please ignore this email." info_text: "Your password won't change until you access the link above and create a new one." unlock_instructions: hello: "Hello" + title: Your account has been locked info_text: "Your account has been locked due to an excessive number of unsuccessful sign in attempts." instructions_text: "Click the link below to unlock your account:" unlock_link: "Unlock my account" @@ -66,6 +69,13 @@ en: phone_number_label: "Phone number" password_confirmation_label: "Confirm password" submit: "Sign up" + success: + title: "Registration of organization / collective" + thank_you: "Thank you for registering your organization or collective in the website. Now is pending verification." + instructions_1_html: "We will contact you soon in order to verify that you represent your collective." + instructions_2_html: "Meanwhile, review your email. We have sent you a confirmation link to activate your account." + instructions_3_html: "When you confirm your account will then be able to participate as a non-verified organization." + back_to_index: "Ok, go back to index" sessions: new: title: "Log in" diff --git a/config/locales/devise_views.es.yml b/config/locales/devise_views.es.yml index 7ed5298de..6ab6ebbb5 100644 --- a/config/locales/devise_views.es.yml +++ b/config/locales/devise_views.es.yml @@ -6,17 +6,20 @@ es: submit: "Reenviar instrucciones de confirmación" mailer: confirmation_instructions: - welcome: "Bienvenido" + title: "Bienvenido/a a gobierno abierto" + welcome: "Bienvenido/a" text: "Puedes confirmar tu cuenta de correo electrónico en el siguiente enlace:" confirm_link: "Confirmar mi cuenta" reset_password_instructions: hello: "Hola" - text: "Se ha solicitado un enlace para cambiar tu contraseña, puedes hacerlo en el siguiente enlace:" - change_link: "cambiar mi contraseña" - ignore_text: "Si tu no lo has solicitado, puedes ignorar este email" + title: "Cambiar tu contraseña" + text: "Se ha solicitado cambiar tu contraseña, puedes hacerlo en el siguiente enlace:" + change_link: "Cambiar mi contraseña" + ignore_text: "Si tu no lo has solicitado, puedes ignorar este email." info_text: "Tu contraseña no cambiará hasta que no accedas al enlace y la modifiques." unlock_instructions: hello: "Hola" + title: Tu cuenta ha sido bloqueada info_text: "Tu cuenta ha sido bloqueada debido a un excesivo número de intentos fallidos de alta." instructions_text: "Sigue el siguiente enlace para desbloquear tu cuenta:" unlock_link: "Desbloquear mi cuenta" @@ -66,6 +69,13 @@ es: phone_number_label: "Teléfono" password_confirmation_label: "Confirmar contraseña" submit: "Registrarse" + success: + title: "Registro de organización / colectivo" + thank_you: "Gracias por registrar tu colectivo en la web. Ahora está pendiente de verificación." + instructions_1_html: "En breve nos pondremos en contacto contigo para verificar que realmente representas a este colectivo." + instructions_2_html: "Mientras revisa tu correo electrónico, te hemos enviado un enlace para confirmar tu cuenta." + instructions_3_html: "Una vez confirmado, podrás empezar a participar como colectivo no verificado." + back_to_index: "Entendido, volver a la página principal" sessions: new: title: "Entrar" diff --git a/config/locales/en.yml b/config/locales/en.yml index ce3339b25..322cf585f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -61,7 +61,6 @@ en: zero: No votes one: 1 vote other: "%{count} votes" - votes_weighted_score: "Total: %{score}" form: debate_title: Debate title title_instructions: "SBe clear and precise with the title, but make it informative" @@ -134,8 +133,8 @@ en: shared: tags_cloud: tags: Topics - flag_as_inappropiate: Flag as inappropiate - undo_flag_as_inappropiate: Undo flag as inappropiate + flag_as_inappropiate: Flag as inappropriate + undo_flag_as_inappropiate: Undo flag collective: Collective mailer: comment: @@ -148,3 +147,12 @@ en: all: "You are not authorized to %{action} %{subject}." welcome: last_debates: Last debates + omniauth: + finish_signup: + title: Add Email + twitter: + sign_in: Sign in with Twitter + facebook: + sign_in: Sign in with Facebook + google_oauth2: + sign_in: Sign in with Google diff --git a/config/locales/es.yml b/config/locales/es.yml index 1e2cca785..5c21c039e 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -61,7 +61,6 @@ es: zero: Sin votos one: 1 voto other: "%{count} votos" - votes_weighted_score: "Total: %{score}" form: debate_title: Título del debate title_instructions: "Sé claro y conciso a la hora de poner un título, pero recuerda que debe explicar bien tu idea, ¡es tu carta de entrada!" @@ -135,7 +134,7 @@ es: tags_cloud: tags: Temas flag_as_inappropiate: Denunciar como inapropiado - undo_flag_as_inappropiate: Deshacer denunciar como inapropiado + undo_flag_as_inappropiate: Deshacer denuncia collective: Colectivo mailer: comment: @@ -148,3 +147,12 @@ es: all: "No tienes permiso para realizar la acción '%{action}' sobre %{subject}." welcome: last_debates: Últimos debates + omniauth: + finish_signup: + title: Añade tu email + twitter: + sign_in: Entra con Twitter + facebook: + sign_in: Entra con Facebook + google_oauth2: + sign_in: Entra con Google diff --git a/config/locales/mailers.en.yml b/config/locales/mailers.en.yml index cbc6c5bd6..d0550aca9 100644 --- a/config/locales/mailers.en.yml +++ b/config/locales/mailers.en.yml @@ -1,8 +1,10 @@ en: mailers: comment: - hi: "Hello, %{recipient}" - new_comment_by: "There'is a new comment by %{commenter}" + hi: Hello + title: New comment on your debate + new_comment_by_html: "There'is a new comment by on" reply: - hi: "Hello, %{recipient}" - new_reply_by: "There'is a new reply by %{commenter} to your comment" \ No newline at end of file + hi: Hello + title: New reply on your comment + new_reply_by_html: "There'is a new reply by %{commenter} to your comment on" diff --git a/config/locales/mailers.es.yml b/config/locales/mailers.es.yml index e595967c4..8efa1dc22 100644 --- a/config/locales/mailers.es.yml +++ b/config/locales/mailers.es.yml @@ -1,8 +1,10 @@ es: mailers: comment: - hi: "Hola, %{recipient}" - new_comment_by: "Hay un nuevo comentario de %{commenter}" + hi: Hola + title: Nuevo comentario en tu debate + new_comment_by_html: "Hay un nuevo comentario de %{commenter} en" reply: - hi: "Hola, %{recipient}" - new_reply_by: "Hay una nueva respuesta de %{commenter} a tu comentario" \ No newline at end of file + hi: Hola + title: Nueva respuesta a tu comentario + new_reply_by_html: "Hay una nueva respuesta de %{commenter} a tu comentario en" diff --git a/config/locales/moderation.en.yml b/config/locales/moderation.en.yml index 2728f10d9..3d61c93a2 100644 --- a/config/locales/moderation.en.yml +++ b/config/locales/moderation.en.yml @@ -8,7 +8,7 @@ en: title: Moderation comments: index: - title: Comments flagged as inappropiate + title: Comments flagged as inappropriate headers: flags: Flags updated_at: Date @@ -16,27 +16,27 @@ en: commentable: Root comment: Comment hide: Hide - mark_as_reviewed: Mark as reviewed - reviewed: Reviewed + archive: Archive + archived: Archived filter: Filter filters: all: All - pending_review: Pending - reviewed: Reviewed + pending: Pending + archived: Archived debates: index: - title: Debates flagged as inappropiate + title: Debates flagged as inappropriate headers: flags: Flags updated_at: Date title: Title description: Description + actions: Actions hide: Hide - mark_as_reviewed: Mark as reviewed - reviewed: Reviewed + archive: Archive + archived: Archived filter: Filter filters: all: All - pending_review: Pending - reviewed: Reviewed - + pending: Pending + archived: Archived diff --git a/config/locales/moderation.es.yml b/config/locales/moderation.es.yml index 2afaec7a9..73886ddb0 100644 --- a/config/locales/moderation.es.yml +++ b/config/locales/moderation.es.yml @@ -8,7 +8,7 @@ es: title: Moderación comments: index: - title: Comentarios Denunciados como Inapropiados + title: Comentarios denunciados como inapropiados headers: flags: Denuncias updated_at: Fecha @@ -16,28 +16,27 @@ es: commentable: Raíz comment: Comentario hide: Ocultar - mark_as_reviewed: Marcar como revisado - reviewed: Revisado + archive: Archivar + archived: Archivado filter: Filtrar filters: all: Todos - pending_review: Pendientes - reviewed: Revisados + pending: Pendientes + archived: Archivados debates: index: - title: Debates Denunciados como Inapropiados + title: Debates denunciados como inapropiados headers: flags: Denuncias updated_at: Fecha title: Título description: Descripción + actions: Acciones hide: Ocultar - mark_as_reviewed: Marcar como revisado - reviewed: Revisado + archive: Archivar + archived: Archivado filter: Filtrar filters: all: Todos - pending_review: Pendientes - reviewed: Revisados - - + pending: Pendientes + archived: Archivados diff --git a/config/routes.rb b/config/routes.rb index 212ab2808..67f3734e9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,10 +1,23 @@ Rails.application.routes.draw do - devise_for :users, controllers: { registrations: 'users/registrations' } + devise_for :users, controllers: { + registrations: 'users/registrations', + omniauth_callbacks: 'users/omniauth_callbacks' + } devise_for :organizations, class_name: 'User', controllers: { registrations: 'organizations/registrations', - sessions: 'devise/sessions' - } + sessions: 'devise/sessions', + }, + skip: [:omniauth_callbacks] + + devise_scope :organization do + get "organizations/sign_up/success", to: "organizations/registrations#success" + end + + devise_scope :user do + get :finish_signup, to: 'users/registrations#finish_signup' + patch :do_finish_signup, to: 'users/registrations#do_finish_signup' + end # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". @@ -79,7 +92,7 @@ Rails.application.routes.draw do member do put :hide put :hide_in_moderation_screen - put :mark_as_reviewed + put :archive end end @@ -87,7 +100,7 @@ Rails.application.routes.draw do member do put :hide put :hide_in_moderation_screen - put :mark_as_reviewed + put :archive end end end diff --git a/config/secrets.yml.example b/config/secrets.yml.example index f4ad98027..1d1312ea6 100644 --- a/config/secrets.yml.example +++ b/config/secrets.yml.example @@ -14,12 +14,30 @@ default: &default development: secret_key_base: 56792feef405a59b18ea7db57b4777e855103882b926413d4afdfb8c0ea8aa86ea6649da4e729c5f5ae324c0ab9338f789174cf48c544173bc18fdc3b14262e4 + twitter_key: AAAA + twitter_secret: BBBB + facebook_key: AAAA + facebook_secret: BBBB + google_oauth2_key: AAAA + google_oauth2_secret: BBBB <<: *default test: secret_key_base: 4d5adf961ddd27aef19622d6c0b3234d555f9ee003f022b1f829c92bbe33aaee907be7feb67bd54c14a1a32512fa968565ad405971fbc41bd0797af73c26a796 + twitter_key: AAAA + twitter_secret: BBBB + facebook_key: AAAA + facebook_secret: BBBB + google_oauth2_key: AAAA + google_oauth2_secret: BBBB <<: *default production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> - <<: *default \ No newline at end of file + twitter_key: <%= ENV["TWITTER_KEY"] %> + twitter_secret: <%= ENV["TWITTER_SECRET"] %> + facebook_key: <%= ENV["FACEBOOK_KEY"] %> + facebook_secret: <%= ENV["FACEBOOK_SECRET"] %> + google_oauth2_key: <%= ENV["GOOGLE_KEY"] %> + google_oauth2_secret: <%= ENV["GOOGLE_SECRET"] %> + <<: *default diff --git a/db/migrate/20150824144524_create_identities.rb b/db/migrate/20150824144524_create_identities.rb new file mode 100644 index 000000000..38a5e603a --- /dev/null +++ b/db/migrate/20150824144524_create_identities.rb @@ -0,0 +1,11 @@ +class CreateIdentities < ActiveRecord::Migration + def change + create_table :identities do |t| + t.references :user, index: true, foreign_key: true + t.string :provider + t.string :uid + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20150825124821_adds_votable_cache_field_to_comments.rb b/db/migrate/20150825124821_adds_votable_cache_field_to_comments.rb new file mode 100644 index 000000000..e2da7e12f --- /dev/null +++ b/db/migrate/20150825124821_adds_votable_cache_field_to_comments.rb @@ -0,0 +1,11 @@ +class AddsVotableCacheFieldToComments < ActiveRecord::Migration + def change + add_column :comments, :cached_votes_total, :integer, default: 0 + add_column :comments, :cached_votes_up, :integer, default: 0 + add_column :comments, :cached_votes_down, :integer, default: 0 + + add_index :comments, :cached_votes_total + add_index :comments, :cached_votes_up + add_index :comments, :cached_votes_down + end +end diff --git a/db/migrate/20150825124827_adds_votable_cache_field_to_debates.rb b/db/migrate/20150825124827_adds_votable_cache_field_to_debates.rb new file mode 100644 index 000000000..07df8cf22 --- /dev/null +++ b/db/migrate/20150825124827_adds_votable_cache_field_to_debates.rb @@ -0,0 +1,11 @@ +class AddsVotableCacheFieldToDebates < ActiveRecord::Migration + def change + add_column :debates, :cached_votes_total, :integer, default: 0 + add_column :debates, :cached_votes_up, :integer, default: 0 + add_column :debates, :cached_votes_down, :integer, default: 0 + + add_index :debates, :cached_votes_total + add_index :debates, :cached_votes_up + add_index :debates, :cached_votes_down + end +end diff --git a/db/migrate/20150826112411_rename_reviewed_at_to_archived_at_in_comments_and_debates.rb b/db/migrate/20150826112411_rename_reviewed_at_to_archived_at_in_comments_and_debates.rb new file mode 100644 index 000000000..86bebd8e1 --- /dev/null +++ b/db/migrate/20150826112411_rename_reviewed_at_to_archived_at_in_comments_and_debates.rb @@ -0,0 +1,6 @@ +class RenameReviewedAtToArchivedAtInCommentsAndDebates < ActiveRecord::Migration + def change + rename_column :comments, :reviewed_at, :archived_at + rename_column :debates, :reviewed_at, :archived_at + end +end diff --git a/db/migrate/20150826112500_add_comments_count_to_debate.rb b/db/migrate/20150826112500_add_comments_count_to_debate.rb new file mode 100644 index 000000000..bf416b669 --- /dev/null +++ b/db/migrate/20150826112500_add_comments_count_to_debate.rb @@ -0,0 +1,5 @@ +class AddCommentsCountToDebate < ActiveRecord::Migration + def change + add_column :debates, :comments_count, :integer, default: 0 + end +end diff --git a/db/schema.rb b/db/schema.rb index 6f4d26c5b..1d7972417 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150824113326) do +ActiveRecord::Schema.define(version: 20150826112500) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -41,7 +41,7 @@ ActiveRecord::Schema.define(version: 20150824113326) do t.string "title" t.text "body" t.string "subject" - t.integer "user_id", null: false + t.integer "user_id", null: false t.integer "parent_id" t.integer "lft" t.integer "rgt" @@ -51,11 +51,17 @@ ActiveRecord::Schema.define(version: 20150824113326) do t.datetime "hidden_at" t.datetime "flagged_as_inappropiate_at" t.integer "inappropiate_flags_count", default: 0 - t.datetime "reviewed_at" + t.datetime "archived_at" t.integer "moderator_id" t.integer "administrator_id" + t.integer "cached_votes_total", default: 0 + t.integer "cached_votes_up", default: 0 + t.integer "cached_votes_down", default: 0 end + add_index "comments", ["cached_votes_down"], name: "index_comments_on_cached_votes_down", using: :btree + add_index "comments", ["cached_votes_total"], name: "index_comments_on_cached_votes_total", using: :btree + add_index "comments", ["cached_votes_up"], name: "index_comments_on_cached_votes_up", using: :btree add_index "comments", ["commentable_id", "commentable_type"], name: "index_comments_on_commentable_id_and_commentable_type", using: :btree add_index "comments", ["hidden_at"], name: "index_comments_on_hidden_at", using: :btree add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree @@ -64,17 +70,34 @@ ActiveRecord::Schema.define(version: 20150824113326) do t.string "title", limit: 80 t.text "description" t.integer "author_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.datetime "hidden_at" t.string "visit_id" t.datetime "flagged_as_inappropiate_at" t.integer "inappropiate_flags_count", default: 0 - t.datetime "reviewed_at" + t.integer "cached_votes_total", default: 0 + t.integer "cached_votes_up", default: 0 + t.integer "cached_votes_down", default: 0 + t.datetime "archived_at" + t.integer "comments_count", default: 0 end + add_index "debates", ["cached_votes_down"], name: "index_debates_on_cached_votes_down", using: :btree + add_index "debates", ["cached_votes_total"], name: "index_debates_on_cached_votes_total", using: :btree + add_index "debates", ["cached_votes_up"], name: "index_debates_on_cached_votes_up", using: :btree add_index "debates", ["hidden_at"], name: "index_debates_on_hidden_at", using: :btree + create_table "identities", force: :cascade do |t| + t.integer "user_id" + t.string "provider" + t.string "uid" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "identities", ["user_id"], name: "index_identities_on_user_id", using: :btree + create_table "inappropiate_flags", force: :cascade do |t| t.integer "user_id" t.string "flaggable_type" @@ -214,7 +237,8 @@ ActiveRecord::Schema.define(version: 20150824113326) do add_index "votes", ["voter_id", "voter_type", "vote_scope"], name: "index_votes_on_voter_id_and_voter_type_and_vote_scope", using: :btree add_foreign_key "administrators", "users" + add_foreign_key "identities", "users" add_foreign_key "inappropiate_flags", "users" add_foreign_key "moderators", "users" add_foreign_key "organizations", "users" -end +end \ No newline at end of file diff --git a/lib/acts_as_paranoid_aliases.rb b/lib/acts_as_paranoid_aliases.rb index dbb0d8350..b4faa19b9 100644 --- a/lib/acts_as_paranoid_aliases.rb +++ b/lib/acts_as_paranoid_aliases.rb @@ -5,11 +5,15 @@ module ActsAsParanoidAliases def hide update_attribute(:hidden_at, Time.now) + after_hide end def hidden? deleted? end + + def after_hide + end end module ClassMethods diff --git a/spec/factories.rb b/spec/factories.rb index 038a0102e..ded2e20a0 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -1,5 +1,4 @@ FactoryGirl.define do - factory :user do username 'Manuela' sequence(:email) { |n| "manuela#{n}@madrid.es" } @@ -7,6 +6,12 @@ FactoryGirl.define do confirmed_at { Time.now } end + factory :identity do + user nil + provider "Twitter" + uid "MyString" + end + factory :debate do sequence(:title) { |n| "Debate #{n} title" } description 'Debate description' @@ -17,8 +22,8 @@ FactoryGirl.define do hidden_at Time.now end - trait :reviewed do - reviewed_at Time.now + trait :archived do + archived_at Time.now end trait :flagged_as_inappropiate do @@ -32,6 +37,9 @@ FactoryGirl.define do association :votable, factory: :debate association :voter, factory: :user vote_flag true + after(:create) do |vote, _| + vote.votable.update_cached_votes + end end factory :comment do @@ -43,8 +51,8 @@ FactoryGirl.define do hidden_at Time.now end - trait :reviewed do - reviewed_at Time.now + trait :archived do + archived_at Time.now end trait :flagged_as_inappropiate do diff --git a/spec/features/comments_spec.rb b/spec/features/comments_spec.rb index 4ed16d915..58626b02b 100644 --- a/spec/features/comments_spec.rb +++ b/spec/features/comments_spec.rb @@ -133,7 +133,7 @@ feature 'Comments' do expect(page).to have_css(".comment.comment.comment.comment.comment.comment.comment.comment") end - scenario "Flagging as inappropiate", :js do + scenario "Flagging as inappropriate", :js do user = create(:user) debate = create(:debate) comment = create(:comment, commentable: debate) @@ -142,15 +142,16 @@ feature 'Comments' do visit debate_path(debate) within "#comment_#{comment.id}" do - expect(page).to_not have_link "Undo flag as inappropiate" - click_on 'Flag as inappropiate' - expect(page).to have_link "Undo flag as inappropiate" + page.find("#flag-expand-comment-#{comment.id}").click + page.find("#flag-comment-#{comment.id}").click + + expect(page).to have_css("#unflag-expand-comment-#{comment.id}") end expect(InappropiateFlag.flagged?(user, comment)).to be end - scenario "Undoing flagging as inappropiate", :js do + scenario "Undoing flagging as inappropriate", :js do user = create(:user) debate = create(:debate) comment = create(:comment, commentable: debate) @@ -160,9 +161,10 @@ feature 'Comments' do visit debate_path(debate) within "#comment_#{comment.id}" do - expect(page).to_not have_link("Flag as inappropiate", exact: true) - click_on 'Undo flag as inappropiate' - expect(page).to have_link("Flag as inappropiate", exact: true) + page.find("#unflag-expand-comment-#{comment.id}").click + page.find("#unflag-comment-#{comment.id}").click + + expect(page).to have_css("#flag-expand-comment-#{comment.id}") end expect(InappropiateFlag.flagged?(user, comment)).to_not be @@ -286,4 +288,4 @@ feature 'Comments' do end end -end \ No newline at end of file +end diff --git a/spec/features/debates_spec.rb b/spec/features/debates_spec.rb index c685725d8..22b689308 100644 --- a/spec/features/debates_spec.rb +++ b/spec/features/debates_spec.rb @@ -323,9 +323,10 @@ feature 'Debates' do visit debate_path(debate) within "#debate_#{debate.id}" do - expect(page).to_not have_link "Undo flag as inappropiate" - click_on 'Flag as inappropiate' - expect(page).to have_link "Undo flag as inappropiate" + page.find("#flag-expand-debate-#{debate.id}").click + page.find("#flag-debate-#{debate.id}").click + + expect(page).to have_css("#unflag-expand-debate-#{debate.id}") end expect(InappropiateFlag.flagged?(user, debate)).to be @@ -340,9 +341,10 @@ feature 'Debates' do visit debate_path(debate) within "#debate_#{debate.id}" do - expect(page).to_not have_link("Flag as inappropiate", exact: true) - click_on 'Undo flag as inappropiate' - expect(page).to have_link("Flag as inappropiate", exact: true) + page.find("#unflag-expand-debate-#{debate.id}").click + page.find("#unflag-debate-#{debate.id}").click + + expect(page).to have_css("#flag-expand-debate-#{debate.id}") end expect(InappropiateFlag.flagged?(user, debate)).to_not be diff --git a/spec/features/moderation/comments_spec.rb b/spec/features/moderation/comments_spec.rb index 5a4100f77..2e3d1196e 100644 --- a/spec/features/moderation/comments_spec.rb +++ b/spec/features/moderation/comments_spec.rb @@ -104,57 +104,57 @@ feature 'Moderate Comments' do visit moderation_comments_path expect(page).to_not have_link('All') expect(page).to have_link('Pending') - expect(page).to have_link('Reviewed') + expect(page).to have_link('Archived') visit moderation_comments_path(filter: 'all') expect(page).to_not have_link('All') expect(page).to have_link('Pending') - expect(page).to have_link('Reviewed') + expect(page).to have_link('Archived') - visit moderation_comments_path(filter: 'pending_review') + visit moderation_comments_path(filter: 'pending') expect(page).to have_link('All') expect(page).to_not have_link('Pending') - expect(page).to have_link('Reviewed') + expect(page).to have_link('Archived') - visit moderation_comments_path(filter: 'reviewed') + visit moderation_comments_path(filter: 'archived') expect(page).to have_link('All') expect(page).to have_link('Pending') - expect(page).to_not have_link('Reviewed') + expect(page).to_not have_link('Archived') end scenario "Filtering comments" do create(:comment, :flagged_as_inappropiate, body: "Pending comment") create(:comment, :flagged_as_inappropiate, :hidden, body: "Hidden comment") - create(:comment, :flagged_as_inappropiate, :reviewed, body: "Reviewed comment") + create(:comment, :flagged_as_inappropiate, :archived, body: "Archived comment") visit moderation_comments_path(filter: 'all') expect(page).to have_content('Pending comment') expect(page).to_not have_content('Hidden comment') - expect(page).to have_content('Reviewed comment') + expect(page).to have_content('Archived comment') - visit moderation_comments_path(filter: 'pending_review') + visit moderation_comments_path(filter: 'pending') expect(page).to have_content('Pending comment') expect(page).to_not have_content('Hidden comment') - expect(page).to_not have_content('Reviewed comment') + expect(page).to_not have_content('Archived comment') - visit moderation_comments_path(filter: 'reviewed') + visit moderation_comments_path(filter: 'archived') expect(page).to_not have_content('Pending comment') expect(page).to_not have_content('Hidden comment') - expect(page).to have_content('Reviewed comment') + expect(page).to have_content('Archived comment') end scenario "Reviewing links remember the pagination setting and the filter" do per_page = Kaminari.config.default_per_page (per_page + 2).times { create(:comment, :flagged_as_inappropiate) } - visit moderation_comments_path(filter: 'pending_review', page: 2) + visit moderation_comments_path(filter: 'pending', page: 2) - click_link('Mark as reviewed', match: :first) + click_link('Archive', match: :first, exact: true) uri = URI.parse(current_url) query_params = Rack::Utils.parse_nested_query(uri.query).symbolize_keys - expect(query_params[:filter]).to eq('pending_review') + expect(query_params[:filter]).to eq('pending') expect(query_params[:page]).to eq('2') end @@ -172,7 +172,7 @@ feature 'Moderate Comments' do expect(page).to have_content('spammy spam') expect(page).to have_content('1') expect(page).to have_link('Hide') - expect(page).to have_link('Mark as reviewed') + expect(page).to have_link('Archive') end end @@ -187,18 +187,18 @@ feature 'Moderate Comments' do expect(@comment.reload).to be_hidden end - scenario 'Marking the comment as reviewed' do + scenario 'Marking the comment as archived' do within("#comment_#{@comment.id}") do - click_link('Mark as reviewed') + click_link('Archive') end expect(current_path).to eq(moderation_comments_path) within("#comment_#{@comment.id}") do - expect(page).to have_content('Reviewed') + expect(page).to have_content('Archived') end - expect(@comment.reload).to be_reviewed + expect(@comment.reload).to be_archived end end end diff --git a/spec/features/moderation/debates_spec.rb b/spec/features/moderation/debates_spec.rb index 1ea3101e0..b1234bb1b 100644 --- a/spec/features/moderation/debates_spec.rb +++ b/spec/features/moderation/debates_spec.rb @@ -47,57 +47,57 @@ feature 'Moderate debates' do visit moderation_debates_path expect(page).to_not have_link('All') expect(page).to have_link('Pending') - expect(page).to have_link('Reviewed') + expect(page).to have_link('Archived') visit moderation_debates_path(filter: 'all') expect(page).to_not have_link('All') expect(page).to have_link('Pending') - expect(page).to have_link('Reviewed') + expect(page).to have_link('Archived') - visit moderation_debates_path(filter: 'pending_review') + visit moderation_debates_path(filter: 'pending') expect(page).to have_link('All') expect(page).to_not have_link('Pending') - expect(page).to have_link('Reviewed') + expect(page).to have_link('Archived') - visit moderation_debates_path(filter: 'reviewed') + visit moderation_debates_path(filter: 'archived') expect(page).to have_link('All') expect(page).to have_link('Pending') - expect(page).to_not have_link('Reviewed') + expect(page).to_not have_link('Archived') end scenario "Filtering debates" do create(:debate, :flagged_as_inappropiate, title: "Pending debate") create(:debate, :flagged_as_inappropiate, :hidden, title: "Hidden debate") - create(:debate, :flagged_as_inappropiate, :reviewed, title: "Reviewed debate") + create(:debate, :flagged_as_inappropiate, :archived, title: "Archived debate") visit moderation_debates_path(filter: 'all') expect(page).to have_content('Pending debate') expect(page).to_not have_content('Hidden debate') - expect(page).to have_content('Reviewed debate') + expect(page).to have_content('Archived debate') - visit moderation_debates_path(filter: 'pending_review') + visit moderation_debates_path(filter: 'pending') expect(page).to have_content('Pending debate') expect(page).to_not have_content('Hidden debate') - expect(page).to_not have_content('Reviewed debate') + expect(page).to_not have_content('Archived debate') - visit moderation_debates_path(filter: 'reviewed') + visit moderation_debates_path(filter: 'archived') expect(page).to_not have_content('Pending debate') expect(page).to_not have_content('Hidden debate') - expect(page).to have_content('Reviewed debate') + expect(page).to have_content('Archived debate') end scenario "Reviewing links remember the pagination setting and the filter" do per_page = Kaminari.config.default_per_page (per_page + 2).times { create(:debate, :flagged_as_inappropiate) } - visit moderation_debates_path(filter: 'pending_review', page: 2) + visit moderation_debates_path(filter: 'pending', page: 2) - click_link('Mark as reviewed', match: :first) + click_link('Archive', match: :first, exact: true) uri = URI.parse(current_url) query_params = Rack::Utils.parse_nested_query(uri.query).symbolize_keys - expect(query_params[:filter]).to eq('pending_review') + expect(query_params[:filter]).to eq('pending') expect(query_params[:page]).to eq('2') end @@ -114,7 +114,7 @@ feature 'Moderate debates' do expect(page).to have_content('buy buy buy') expect(page).to have_content('1') expect(page).to have_link('Hide') - expect(page).to have_link('Mark as reviewed') + expect(page).to have_link('Archive') end end @@ -129,18 +129,18 @@ feature 'Moderate debates' do expect(@debate.reload).to be_hidden end - scenario 'Marking the debate as reviewed' do + scenario 'Marking the debate as archived' do within("#debate_#{@debate.id}") do - click_link('Mark as reviewed') + click_link('Archive') end expect(current_path).to eq(moderation_debates_path) within("#debate_#{@debate.id}") do - expect(page).to have_content('Reviewed') + expect(page).to have_content('Archived') end - expect(@debate.reload).to be_reviewed + expect(@debate.reload).to be_archived end end end diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb index 42511f28c..1fa30bcbe 100644 --- a/spec/features/users_spec.rb +++ b/spec/features/users_spec.rb @@ -2,44 +2,159 @@ require 'rails_helper' feature 'Users' do - scenario 'Sign up' do - visit '/' - click_link 'Sign up' + context 'Regular authentication' do + scenario 'Sign up' do + visit '/' + click_link 'Sign up' - fill_in 'user_username', with: 'Manuela Carmena' - fill_in 'user_email', with: 'manuela@madrid.es' - fill_in 'user_password', with: 'judgementday' - fill_in 'user_password_confirmation', with: 'judgementday' - fill_in 'user_captcha', with: correct_captcha_text + fill_in 'user_username', with: 'Manuela Carmena' + fill_in 'user_email', with: 'manuela@madrid.es' + fill_in 'user_password', with: 'judgementday' + fill_in 'user_password_confirmation', with: 'judgementday' + fill_in 'user_captcha', with: correct_captcha_text - click_button 'Sign up' + click_button 'Sign up' - expect(page).to have_content "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account." + expect(page).to have_content "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account." - sent_token = /.*confirmation_token=(.*)".*/.match(ActionMailer::Base.deliveries.last.body.to_s)[1] - visit user_confirmation_path(confirmation_token: sent_token) + sent_token = /.*confirmation_token=(.*)".*/.match(ActionMailer::Base.deliveries.last.body.to_s)[1] + visit user_confirmation_path(confirmation_token: sent_token) - expect(page).to have_content "Your email address has been successfully confirmed" + expect(page).to have_content "Your email address has been successfully confirmed" + end + + scenario 'Errors on sign up' do + visit '/' + click_link 'Sign up' + click_button 'Sign up' + + expect(page).to have_content error_message + end + + scenario 'Sign in' do + create(:user, email: 'manuela@madrid.es', password: 'judgementday') + + visit '/' + click_link 'Log in' + fill_in 'user_email', with: 'manuela@madrid.es' + fill_in 'user_password', with: 'judgementday' + click_button 'Log in' + + expect(page).to have_content 'Signed in successfully.' + end end - scenario 'Errors on sign up' do - visit '/' - click_link 'Sign up' - click_button 'Sign up' + context 'OAuth authentication' do + context 'Twitter' do + background do + #request.env["devise.mapping"] = Devise.mappings[:user] + end - expect(page).to have_content error_message - end + scenario 'Sign up, when email was provided by OAuth provider' do + omniauth_twitter_hash = { 'provider' => 'twitter', + 'uid' => '12345', + 'info' => { + 'name' => 'manuela', + 'email' => 'manuelacarmena@example.com', + 'nickname' => 'ManuelaRocks', + 'verified' => '1' + }, + 'extra' => { 'raw_info' => + { 'location' => 'Madrid', + 'name' => 'Manuela de las Carmenas' + } + } + } - scenario 'Sign in' do - create(:user, email: 'manuela@madrid.es', password: 'judgementday') + OmniAuth.config.add_mock(:twitter, omniauth_twitter_hash) - visit '/' - click_link 'Log in' - fill_in 'user_email', with: 'manuela@madrid.es' - fill_in 'user_password', with: 'judgementday' - click_button 'Log in' + visit '/' + click_link 'Sign up' - expect(page).to have_content 'Signed in successfully.' + expect do + expect do + expect do + click_link 'Sign in with Twitter' + end.not_to change { ActionMailer::Base.deliveries.size } + end.to change { Identity.count }.by(1) + end.to change { User.count }.by(1) + + expect(current_path).to eq(root_path) + expect_to_be_signed_in + + user = User.last + expect(user.username).to eq('ManuelaRocks') + expect(user.email).to eq('manuelacarmena@example.com') + expect(user.confirmed?).to eq(true) + end + + scenario 'Sign up, when neither email nor nickname were provided by OAuth provider' do + omniauth_twitter_hash = { 'provider' => 'twitter', + 'uid' => '12345', + 'info' => { + 'name' => 'manuela' + }, + 'extra' => { 'raw_info' => + { 'location' => 'Madrid', + 'name' => 'Manuela de las Carmenas' + } + } + } + + OmniAuth.config.add_mock(:twitter, omniauth_twitter_hash) + + visit '/' + click_link 'Sign up' + + expect do + expect do + expect do + click_link 'Sign in with Twitter' + end.not_to change { ActionMailer::Base.deliveries.size } + end.to change { Identity.count }.by(1) + end.to change { User.count }.by(1) + + expect(current_path).to eq(finish_signup_path) + + user = User.last + expect(user.username).to eq('manuela-de-las-carmenas') + expect(user.email).to eq("omniauth@participacion-12345-twitter.com") + + fill_in 'user_email', with: 'manueladelascarmenas@example.com' + click_button 'Sign up' + + sent_token = /.*confirmation_token=(.*)".*/.match(ActionMailer::Base.deliveries.last.body.to_s)[1] + visit user_confirmation_path(confirmation_token: sent_token) + + expect(page).to have_content "Your email address has been successfully confirmed" + + expect(user.reload.email).to eq('manueladelascarmenas@example.com') + end + + scenario 'Sign in, user was already signed up with OAuth' do + user = create(:user, email: 'manuela@madrid.es', password: 'judgementday') + identity = create(:identity, uid: '12345', provider: 'twitter', user: user) + omniauth_twitter_hash = { 'provider' => 'twitter', + 'uid' => '12345', + 'info' => { + 'name' => 'manuela' + } + } + + OmniAuth.config.add_mock(:twitter, omniauth_twitter_hash) + + visit '/' + click_link 'Log in' + + expect do + expect do + click_link 'Sign in with Twitter' + end.not_to change { Identity.count } + end.not_to change { User.count } + + expect_to_be_signed_in + end + end end scenario 'Sign out' do @@ -73,5 +188,4 @@ feature 'Users' do expect(page).to have_content "Your password has been changed successfully. You are now signed in." end - end diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index ff3e3800c..a7cfd195f 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -131,8 +131,8 @@ describe Ability do let(:own_debate) { create(:debate, author: user) } let(:hidden_comment) { create(:comment, :hidden) } let(:hidden_debate) { create(:debate, :hidden) } - let(:reviewed_comment) { create(:comment, :reviewed) } - let(:reviewed_debate) { create(:debate, :reviewed) } + let(:archived_comment) { create(:comment, :archived) } + let(:archived_debate) { create(:debate, :archived) } it { should be_able_to(:hide, comment) } it { should be_able_to(:hide_in_moderation_screen, comment) } @@ -144,15 +144,15 @@ describe Ability do it { should_not be_able_to(:hide, hidden_debate) } it { should_not be_able_to(:hide, own_debate) } - it { should be_able_to(:mark_as_reviewed, comment) } - it { should_not be_able_to(:mark_as_reviewed, hidden_comment) } - it { should_not be_able_to(:mark_as_reviewed, reviewed_comment) } - it { should_not be_able_to(:mark_as_reviewed, own_comment) } + it { should be_able_to(:archive, comment) } + it { should_not be_able_to(:archive, hidden_comment) } + it { should_not be_able_to(:archive, archived_comment) } + it { should_not be_able_to(:archive, own_comment) } - it { should be_able_to(:mark_as_reviewed, debate) } - it { should_not be_able_to(:mark_as_reviewed, hidden_debate) } - it { should_not be_able_to(:mark_as_reviewed, reviewed_debate) } - it { should_not be_able_to(:mark_as_reviewed, own_debate) } + it { should be_able_to(:archive, debate) } + it { should_not be_able_to(:archive, hidden_debate) } + it { should_not be_able_to(:archive, archived_debate) } + it { should_not be_able_to(:archive, own_debate) } it { should_not be_able_to(:hide, user) } it { should be_able_to(:hide, other_user) } diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb index 98420c000..4115fedcf 100644 --- a/spec/models/comment_spec.rb +++ b/spec/models/comment_spec.rb @@ -8,6 +8,15 @@ describe Comment do expect(comment).to be_valid end + it "should update cache_counter in debate after hide" do + debate = create(:debate) + comment = create(:comment, commentable: debate) + + expect(debate.reload.comments_count).to eq(1) + comment.hide + expect(debate.reload.comments_count).to eq(0) + end + describe "#children_count" do let(:comment) { create(:comment) } let(:debate) { comment.debate } diff --git a/spec/models/identity_spec.rb b/spec/models/identity_spec.rb new file mode 100644 index 000000000..82d5c4be3 --- /dev/null +++ b/spec/models/identity_spec.rb @@ -0,0 +1,9 @@ +require 'rails_helper' + +RSpec.describe Identity, type: :model do + let(:identity) { build(:identity) } + + it "should be valid" do + expect(identity).to be_valid + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 5a4bbdf88..e0260285a 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -50,6 +50,26 @@ describe User do end end + describe 'OmniAuth' do + describe '#email_provided?' do + it "is false if the email matchs was temporarely assigned by the OmniAuth process" do + subject.email = 'omniauth@participacion-ABCD-twitter.com' + expect(subject.email_provided?).to eq(false) + end + + it "is true if the email is not omniauth-like" do + subject.email = 'manuelacarmena@example.com' + expect(subject.email_provided?).to eq(true) + end + + it "is true if the user's real email is pending to be confirmed" do + subject.email = 'omniauth@participacion-ABCD-twitter.com' + subject.unconfirmed_email = 'manuelacarmena@example.com' + expect(subject.email_provided?).to eq(true) + end + end + end + describe "administrator?" do it "is false when the user is not an admin" do expect(subject.administrator?).to be false diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index d073cc173..c2f5db0fe 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -22,3 +22,5 @@ RSpec.configure do |config| end Capybara.javascript_driver = :poltergeist + +OmniAuth.config.test_mode = true diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0e0b14960..bf1a65776 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -27,6 +27,15 @@ RSpec.configure do |config| DatabaseCleaner.clean end + config.before(:each, type: :feature) do + Bullet.start_request + end + + config.after(:each, type: :feature) do + Bullet.perform_out_of_channel_notifications if Bullet.notification? + Bullet.end_request + end + # Allows RSpec to persist some state between runs in order to support # the `--only-failures` and `--next-failure` CLI options. config.example_status_persistence_file_path = "spec/examples.txt" @@ -57,4 +66,6 @@ RSpec.configure do |config| # test failures related to randomization by passing the same `--seed` value # as the one that triggered the failure. Kernel.srand config.seed + + end diff --git a/spec/support/common_actions.rb b/spec/support/common_actions.rb index 21a98f56f..12d6affd3 100644 --- a/spec/support/common_actions.rb +++ b/spec/support/common_actions.rb @@ -77,4 +77,7 @@ module CommonActions /\d errors? prohibited this (.*) from being saved:/ end + def expect_to_be_signed_in + expect(find('.top-bar')).to have_content 'My account' + end end