Merge branch 'master' of github.com:AyuntamientoMadrid/participacion

This commit is contained in:
Jose Manuel
2015-08-26 21:40:44 +01:00
91 changed files with 1170 additions and 360 deletions

10
Gemfile
View File

@@ -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

View File

@@ -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)

View File

@@ -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))

View File

@@ -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

Binary file not shown.

View File

@@ -29,4 +29,5 @@
<glyph unicode="&#117;" d="M165 384c0 10-4 19-11 26-7 7-16 11-26 11-10 0-19-4-26-11-7-7-11-16-11-26 0-10 4-19 11-26 7-7 16-11 26-11 10 0 19 4 26 11 7 7 11 16 11 26z m304-165c0-10-3-18-10-25l-140-141c-8-7-17-10-26-10-11 0-19 3-26 10l-204 205c-8 7-14 16-19 29-5 12-7 23-7 33l0 119c0 10 3 18 10 26 8 7 16 10 26 10l119 0c10 0 21-2 33-7 13-5 22-11 30-19l204-204c7-7 10-16 10-26z"/>
<glyph unicode="&#112;" d="M475 238c-29 45-65 78-108 101 11-20 17-42 17-65 0-35-13-65-38-90-25-25-55-38-90-38-35 0-65 13-90 38-25 25-38 55-38 90 0 23 6 45 17 65-43-23-79-56-108-101 25-39 57-70 95-94 38-23 79-34 124-34 45 0 86 11 124 34 38 24 70 55 95 94z m-205 109c0 4-2 7-4 10-3 3-6 4-10 4-24 0-44-8-61-25-17-17-26-38-26-62 0-4 1-7 4-9 3-3 6-4 10-4 4 0 7 1 10 4 2 2 4 5 4 9 0 17 5 31 17 42 12 12 26 18 42 18 4 0 7 1 10 4 2 2 4 6 4 9z m242-109c0-7-2-13-6-20-26-44-62-79-107-105-45-27-93-40-143-40-50 0-98 13-143 40-45 26-81 61-107 105-4 7-6 13-6 20 0 6 2 13 6 19 26 44 62 79 107 106 45 26 93 39 143 39 50 0 98-13 143-39 45-27 81-62 107-106 4-6 6-13 6-19z"/>
<glyph unicode="&#118;" d="M426 134c0-7-3-14-8-19l-39-39c-5-5-12-8-20-8-7 0-14 3-19 8l-84 84-84-84c-5-5-12-8-19-8-8 0-15 3-20 8l-39 39c-5 5-8 12-8 19 0 8 3 14 8 20l84 84-84 84c-5 5-8 12-8 19 0 8 3 14 8 20l39 38c5 6 12 8 20 8 7 0 14-2 19-8l84-84 84 84c5 6 12 8 19 8 8 0 15-2 20-8l39-38c5-6 8-12 8-20 0-7-3-14-8-19l-84-84 84-84c5-6 8-12 8-20z"/>
<glyph unicode="&#119;" d="M434 389c-1 0-2 0-3 0l0 0c-17-9-37-14-58-14-38 0-73 17-95 45-21 19-49 31-80 31-29 0-56-11-77-29-4 9-13 15-24 15-15 0-27-12-27-27l0-322c0-15 12-27 27-27 15 0 27 12 27 27l0 145c17 9 36 13 56 13 39 0 73-17 96-45 21-19 49-31 79-31 33 0 63 14 84 36 2 2 3 4 3 6l0 169c0 5-4 8-8 8z"/>
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -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 {

View File

@@ -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;
}

View File

@@ -103,3 +103,7 @@
.icon-x:before {
content: "v";
}
.icon-flag:before {
content: "w";
}

View File

@@ -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 {

View File

@@ -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);

View File

@@ -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
end

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

17
app/models/identity.rb Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -26,7 +26,7 @@
<div class="small-12 medium-6 column">
<h2><%= t("account.show.avatar")%></h2>
<%= avatar_image(@account, size: 100) %>
<%= avatar_image(@account, seed: @account.id, size: 100) %>
<h2><%= t("account.show.notifications")%></h2>

View File

@@ -1,12 +1,16 @@
<span class="js-flag-as-inappropiate-actions">
<%= render 'comments/flag_as_inappropiate_actions', comment: comment %>
</span>
<span class='js-moderation-actions'>
<% if can? :hide, comment %>
&nbsp;|&nbsp;
<span class="divider">&nbsp;&bullet;&nbsp;</span>
<%= 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 %>
&nbsp;|&nbsp;
<span class="divider">&nbsp;&bullet;&nbsp;</span>
<%= 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 %>

View File

@@ -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? %>
<i class="icon-deleted user-deleted"></i>
@@ -58,10 +58,6 @@
<% end %>
&nbsp;&bullet;&nbsp;<%= time_ago_in_words(comment.created_at) %>
<span class="right js-flag-as-inappropiate-actions">
<%= render 'comments/flag_as_inappropiate_actions', comment: comment %>
</span>
</div>
<% if comment.as_administrator? %>
@@ -81,11 +77,11 @@
<%= render 'comments/votes', comment: comment %>
</span>
<p class="reply">
<div class="reply">
<%= t("debates.comment.responses", count: comment.children_count) %>
<% if user_signed_in? %>
&nbsp;|&nbsp;
<span class="divider">&nbsp;|&nbsp;</span>
<%= 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 %>
</p>
</div>
</div>
<% end %>
<div class="comment-children">
<%= render comment.children.with_hidden.reorder('id DESC, lft') %>
<%= render comment.children.for_render.reorder('id DESC, lft') %>
</div>
</div>
</div>

View File

@@ -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 %>
<span class="divider">&nbsp;|&nbsp;</span>
<a id="flag-expand-comment-<%= comment.id %>" data-dropdown="flag-drop-comment-<%= comment.id %>" aria-controls="flag-drop-comment-<%= comment.id %>" aria-expanded="false" title="<%= t('shared.flag_as_inappropiate') %>">
&nbsp;<i class="icon-flag flag-disable"></i>&nbsp;&nbsp;
</a>
<ul id="flag-drop-comment-<%= comment.id %>" class="f-dropdown" data-dropdown-content aria-hidden="true" tabindex="-1">
<li>
<%= link_to t("shared.flag_as_inappropiate"), flag_as_inappropiate_comment_path(comment), method: :put, remote: true, id: "flag-comment-#{comment.id}" %>
</li>
</ul>
<% 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 %>
<span class="divider">&nbsp;|&nbsp;</span>
<a id="unflag-expand-comment-<%= comment.id %>" data-dropdown="unflag-drop-comment-<%= comment.id %>" aria-controls="unflag-drop-comment-<%= comment.id %>" aria-expanded="false" title="<%= t('shared.undo_flag_as_inappropiate') %>">
&nbsp;<i class="icon-flag flag-active"></i>&nbsp;&nbsp;
</a>
<ul id="unflag-drop-comment-<%= comment.id %>" class="f-dropdown" data-dropdown-content aria-hidden="true" tabindex="-1">
<li>
<%= link_to t("shared.undo_flag_as_inappropiate"), undo_flag_as_inappropiate_comment_path(comment), method: :put, remote: true, id: "unflag-comment-#{comment.id}" %>
</li>
</ul>
<% end %>

View File

@@ -1,5 +1,4 @@
<span>
<!-- <%= t('debates.comment.votes_weighted_score', score: comment.weighted_score) %> -->
<%= t('debates.comment.votes', count: comment.total_votes) %>
</span>
&nbsp;|&nbsp;
@@ -8,7 +7,7 @@
method: "post", remote: true do %>
<i class="icon-angle-up"></i>
<% end %>
<%= comment.get_likes.size %>
<%= comment.total_likes %>
</span>
<span class="against">
@@ -16,5 +15,5 @@
method: "post", remote: true do %>
<i class="icon-angle-down"></i>
<% end %>
<%= comment.get_dislikes.size %>
<%= comment.total_dislikes %>
</span>

View File

@@ -9,7 +9,7 @@
<h3><%= link_to debate.title, debate %></h3>
<p class="debate-info">
<i class="icon-comments"></i>&nbsp;
<%= 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") %>
</p>
<div class="debate-description">
<%= link_to debate.description, debate %>

View File

@@ -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 %>
<a id="flag-expand-debate-<%= debate.id %>" data-dropdown="flag-drop-debate-<%= debate.id %>" aria-controls="flag-drop-debate-<%= debate.id %>" aria-expanded="false" title="<%= t('shared.flag_as_inappropiate') %>">
&nbsp;<i class="icon-flag flag-disable"></i>&nbsp;&nbsp;
</a>
<ul id="flag-drop-debate-<%= debate.id %>" class="f-dropdown" data-dropdown-content aria-hidden="true" tabindex="-1">
<li>
<%= link_to t('shared.flag_as_inappropiate'), flag_as_inappropiate_debate_path(debate), method: :put, remote: true, id: "flag-debate-#{ debate.id }" %>
</li>
</ul>
<% 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 %>
<a id="unflag-expand-debate-<%= debate.id %>" data-dropdown="unflag-drop-debate-<%= debate.id %>" aria-controls="unflag-drop-debate-<%= debate.id %>" aria-expanded="false" title="<%= t('shared.undo_flag_as_inappropiate') %>">
&nbsp;<i class="icon-flag flag-active"></i>&nbsp;&nbsp;
</a>
<ul id="unflag-drop-debate-<%= debate.id %>" class="f-dropdown" data-dropdown-content aria-hidden="true" tabindex="-1">
<li>
<%= link_to t('shared.undo_flag_as_inappropiate'), undo_flag_as_inappropiate_debate_path(debate), method: :put, remote: true, id: "unflag-debate-#{ debate.id }" %>
</li>
</ul>
<% end %>

View File

@@ -13,7 +13,7 @@
<h1><%= @debate.title %></h1>
<div class="debate-info">
<%= 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? %>
<i class="icon-deleted author-deleted"></i>
<span class="author">
@@ -40,9 +40,9 @@
<%= l @debate.created_at.to_date %>
<span class="bullet">&nbsp;&bullet;&nbsp;</span>
<i class="icon-comments"></i>&nbsp;
<%= link_to t("debates.show.comments", count: @debate.comment_threads.count), "#comments" %>
<span class='right js-flag-as-inappropiate-actions'>
<%= link_to t("debates.show.comments", count: @debate.comments_count), "#comments" %>
<span class="bullet">&nbsp;&bullet;&nbsp;</span>
<span class="js-flag-as-inappropiate-actions">
<%= render 'debates/flag_as_inappropiate_actions', debate: @debate %>
</span>
</div>
@@ -79,7 +79,7 @@
<h2>
<%= t("debates.show.comments_title") %>
<span>(<%= @debate.comment_threads.count %>)</span>
<span>(<%= @debate.comments_count %>)</span>
</h2>
<% if user_signed_in? %>
<%= render 'comments/form', {parent: @debate, toggeable: false} %>

View File

@@ -0,0 +1,7 @@
<br/>
<%= 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' %>
<hr/>

View File

@@ -1,5 +1,18 @@
<p><%= t("devise_views.mailer.confirmation_instructions.welcome") %> <%= @email %></p>
<td style="padding-bottom: 20px; padding-left: 10px;">
<p><%= t("devise_views.mailer.confirmation_instructions.text") %></p>
<h1 style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;">
<%= t("devise_views.mailer.confirmation_instructions.title") %>
</h1>
<p><%= link_to t("devise_views.mailer.confirmation_instructions.confirm_link"), confirmation_url(@resource, confirmation_token: @token) %></p>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= t("devise_views.mailer.confirmation_instructions.welcome") %> <strong><%= @email %></strong>
</p>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= t("devise_views.mailer.confirmation_instructions.text") %>
</p>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= link_to t("devise_views.mailer.confirmation_instructions.confirm_link"), confirmation_url(@resource, confirmation_token: @token), style: "color: #2895F1; text-decoration:none;" %>
</p>
</td>

View File

@@ -1,8 +1,22 @@
<p><%= t("devise_views.mailer.reset_password_instructions.hello") %> <%= @resource.email %></p>
<td style="padding-bottom: 20px; padding-left: 10px;">
<p><%= t("devise_views.mailer.reset_password_instructions.text") %></p>
<h1 style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;">
<%= t("devise_views.mailer.reset_password_instructions.title") %>
</h1>
<p><%= link_to t("devise_views.mailer.reset_password_instructions.change_link"), edit_password_url(@resource, reset_password_token: @token) %></p>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= t("devise_views.mailer.reset_password_instructions.hello") %> <strong><%= @resource.email %></strong>
</p>
<p><%= t("devise_views.mailer.reset_password_instructions.ignore_text") %></p>
<p><%= t("devise_views.mailer.reset_password_instructions.info_text") %></p>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= t("devise_views.mailer.reset_password_instructions.text") %>
</p>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= 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;" %>
</p>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= t("devise_views.mailer.reset_password_instructions.ignore_text") %> <%= t("devise_views.mailer.reset_password_instructions.info_text") %>
</p>
</td>

View File

@@ -1,7 +1,22 @@
<p><%= t("devise_views.mailer.unlock_instructions.hello") %> <%= @resource.email %></p>
<td style="padding-bottom: 20px; padding-left: 10px;">
<p><%= t("devise_views.mailer.unlock_instructions.info_text") %></p>
<h1 style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;">
<%= t("devise_views.mailer.unlock_instructions.title") %>
</h1>
<p><%= t("devise_views.mailer.unlock_instructions.instructions_text") %></p>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= t("devise_views.mailer.unlock_instructions.hello") %> <strong><%= @resource.email %></strong>
</p>
<p><%= link_to t("devise_views.mailer.unlock_instructions.unlock_link"), unlock_url(@resource, unlock_token: @token) %></p>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= t("devise_views.mailer.unlock_instructions.info_text") %>
</p>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= t("devise_views.mailer.unlock_instructions.instructions_text") %>
</p>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= link_to t("devise_views.mailer.unlock_instructions.unlock_link"), unlock_url(@resource, unlock_token: @token), style: "color: #2895F1; text-decoration:none;" %>
</p>
</td>

View File

@@ -7,11 +7,11 @@
<%= link_to(t("devise_views.menu.login_items.logout"), destroy_user_session_path, method: :delete) %>
</li>
<% else %>
<li>
<%= link_to(t("devise_views.menu.login_items.login"), new_user_session_path) %>
</li>
<li>
<%= link_to(t("devise_views.menu.login_items.signup"), new_user_registration_path, class: "button radius small") %>
</li>
<li>
<%= link_to(t("devise_views.menu.login_items.login"), new_user_session_path) %>
</li>
<li>
<%= link_to(t("devise_views.menu.login_items.signup"), new_user_registration_path, class: "button radius small") %>
</li>
<% end %>
</ul>
</ul>

View File

@@ -19,4 +19,4 @@
<%= render "devise/shared/links" %>
</div>
</div>
</div>
</div>

View File

@@ -3,6 +3,8 @@
<div class="panel">
<h2><%= t("devise_views.sessions.new.title") %></h2>
<%= render 'devise/omniauth_form' %>
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<div class="row">
<div class="small-12 columns">
@@ -28,4 +30,4 @@
<%= render "devise/shared/links" %>
</div>
</div>
</div>
</div>

View File

@@ -25,7 +25,7 @@
<%= link_to t("devise_views.shared.links.new_unlock"), new_unlock_path(resource_name) %><br>
<% 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) %><br>
<% end -%>

View File

@@ -1,5 +1,42 @@
<html>
<body>
<%= yield %>
</body>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="es">
<head>
<title>Gobierno abierto</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="viewport" id="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0,maximum-scale=10.0"/>
</head>
<body style="background: #fff; font-family:font-family: 'Open Sans','Helvetica Neue',arial,sans-serif !important; margin: 0 10px; padding: 0; text-align: left;">
<table cellpadding="0" cellspacing="0" border="0" style="background: #fff; margin: 0 auto; max-width: 700px; width:100%;">
<tr>
<td>
<table cellpadding="0" cellspacing="0" border="0" style="width: 100%;">
<tr>
<td style="border-bottom: 1px solid #dadfe1; padding: 20px 0;">
<a href="#" target="_blank">
<%= image_tag('logo_email_gobierno_abierto.png', style: "border: 0; display: block; width: 100%;max-width: 370px") %>
</a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<%= yield %>
</tr>
</table>
<table cellpadding="0" cellspacing="0" border="0" style="margin: 0 auto; max-width: 700px; width:100%; margin-bottom: 40px; padding: 0 20px;">
<tbody>
<tr>
<td style="text-align: center; border-top: 1px solid #dadfe1; padding-top: 20px;">
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif; margin: 0;padding: 0;line-height: 1.5em;color: #797f7f; font-size: 12px;">
<a href="#" style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;margin: 0;padding: 0;color: #398fd1;text-decoration: none;">Preguntas frecuentes</a>&nbsp;<span style="color:#398fd1;">&bullet;</span>&nbsp;<a href="mailto:#" style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;margin: 0;padding: 0;color: #398fd1;text-decoration: none;">tec.gobiernoabierto@madrid.es</a></p>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif; margin: 0;padding: 0;line-height: 1.5em;color: #797f7f; font-size: 12px;">
&copy; 2015 Ayuntamiento de Madrid</p>
</td>
</tr>
</tbody>
</table>
</body>
</html>

View File

@@ -1,6 +1,18 @@
<%= t('mailers.comment.hi', recipient: @debate.author.name) %>
<td style="padding-bottom: 20px; padding-left: 10px;">
<div><%= link_to @debate.title, debate_url(@debate) %></div>
<div><%= t('mailers.comment.new_comment_by', commenter: @comment.author.name) %></div>
<h1 style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;">
<%= t("mailers.comment.title") %>
</h1>
<div><%= @comment.body %></div>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= t("mailers.comment.hi") %> <strong><%= @debate.author.name %></strong>,
</p>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= t("mailers.comment.new_comment_by_html", commenter: @comment.author.name) %> <%= link_to @debate.title, debate_url(@debate), style: "color: #2895F1; text-decoration:none;" %>
</p>
<p style="border-left: 2px solid #DEE0E3;font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-style: italic;font-weight: normal;line-height: 24px;margin-left: 20px;padding: 10px;">
<%= @comment.body %>
</p>
</td>

View File

@@ -1,6 +1,18 @@
<%= t('mailers.reply.hi', recipient: @recipient.name) %>
<td style="padding-bottom: 20px; padding-left: 10px;">
<div><%= link_to @debate.title, debate_url(@debate) %></div>
<div><%= t('mailers.reply.new_reply_by', commenter: @reply.author.name) %></div>
<h1 style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;">
<%= t("mailers.reply.title") %>
</h1>
<div><%= @reply.body %></div>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= t("mailers.reply.hi") %> <strong><%= @recipient.name %></strong>,
</p>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= t("mailers.reply.new_reply_by_html", commenter: @reply.author.name) %> <%= link_to @debate.title, debate_url(@debate), style: "color: #2895F1; text-decoration:none;" %>
</p>
<p style="border-left: 2px solid #DEE0E3;font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-style: italic;font-weight: normal;line-height: 24px;margin-left: 20px;padding: 10px;">
<%= @reply.body %>
</p>
</td>

View File

@@ -4,17 +4,17 @@
<%= t("moderation.dashboard.index.title") %>
</li>
<li <%= 'class=active' if controller_name == 'debates' %>>
<li <%= "class=active" if controller_name == "debates" %>>
<%= link_to moderation_debates_path do %>
<i class="icon-eye"></i>
<i class="icon-debates"></i>
<%= t('moderation.menu.flagged_debates') %>
<% end %>
</li>
<li <%= 'class=active' if controller_name == 'comments' %>>
<li <%= "class=active" if controller_name == "comments" %>>
<%= link_to moderation_comments_path do %>
<i class="icon-comment-quotes"></i>
<%= t('moderation.menu.flagged_comments') %>
<i class="icon-comments"></i>
<%= t("moderation.menu.flagged_comments") %>
<% end %>
</li>
</ul>

View File

@@ -1,45 +1,52 @@
<h2><%= t('moderation.comments.index.title') %></h2>
<h2><%= t("moderation.comments.index.title") %></h2>
<dl class="sub-nav">
<dt><%= t("moderation.comments.index.filter") %>:</dt>
<p>
<%= t('moderation.comments.index.filter') %>:
<% @valid_filters.each do |filter| %>
<% if @filter == filter %>
<%= t("moderation.comments.index.filters.#{filter}") %>
<dd class="active"><%= t("moderation.comments.index.filters.#{filter}") %></dd>
<% else %>
<%= link_to t("moderation.comments.index.filters.#{filter}"),
moderation_comments_path(filter: filter) %>
<dd><%= link_to t("moderation.comments.index.filters.#{filter}"),
moderation_comments_path(filter: filter) %></dd>
<% end %>
<% end %>
</p>
</dl>
<h3><%= page_entries_info @comments %></h3>
<table>
<tr>
<th><%= t('moderation.comments.index.headers.flags') %></th>
<th><%= t('moderation.comments.index.headers.updated_at') %></th>
<th><%= t('moderation.comments.index.headers.commentable_type') %></th>
<th><%= t('moderation.comments.index.headers.commentable') %></th>
<th><%= t('moderation.comments.index.headers.comment') %></th>
<th>
<%= t("moderation.comments.index.headers.commentable") %>&nbsp;|&nbsp;
<%= t("moderation.comments.index.headers.commentable_type") %>&nbsp;|&nbsp;
<%= t("moderation.comments.index.headers.updated_at") %>
</th>
<th><%= t("moderation.comments.index.headers.comment") %></th>
<th class="text-center"><%= t("moderation.comments.index.headers.flags") %></th>
<th class="text-center" colspan="2"><%= t("moderation.debates.index.headers.actions") %></th>
</tr>
<% @comments.each do |comment| %>
<tr id="comment_<%= comment.id %>">
<td><%= comment.inappropiate_flags_count %></td>
<td><%= l comment.updated_at.to_date %></td>
<td><%= comment.commentable_type.constantize.model_name.human %></td>
<td><%= link_to comment.commentable.title, comment.commentable %></td>
<td><%= comment.body %></td>
<td>
<%= 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 %>
<br>
<%= comment.commentable_type.constantize.model_name.human %>
<span class="date"><%= l comment.updated_at.to_date %></span>
</td>
<% if can? :mark_as_reviewed, comment %>
<td><%= comment.body %></td>
<td class="text-center"><%= comment.inappropiate_flags_count %></td>
<td>
<%= link_to t("moderation.comments.index.hide"), hide_in_moderation_screen_moderation_comment_path(comment, request.query_parameters), method: :put, class: "delete" %>
</td>
<% if can? :archive, comment %>
<td>
<%= 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" %>
</td>
<% end %>
<% if comment.reviewed? %>
<td>
<%= t('moderation.comments.index.reviewed') %>
<% if comment.archived? %>
<td class="archived">
<%= t("moderation.comments.index.archived") %>
</td>
<% end %>
</tr>
@@ -47,4 +54,3 @@
</table>
<%= paginate @comments %>

View File

@@ -1 +1,5 @@
<h1><%= t("moderation.dashboard.index.title") %></h1>
<h2><%= t("moderation.dashboard.index.title") %></h2>
<p>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.</p>
<p>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.</p>

View File

@@ -1,43 +1,51 @@
<h2><%= t('moderation.debates.index.title') %></h2>
<h2><%= t("moderation.debates.index.title") %></h2>
<dl class="sub-nav">
<dt><%= t("moderation.debates.index.filter") %>:</dt>
<p>
<%= t('moderation.debates.index.filter') %>:
<% @valid_filters.each do |filter| %>
<% if @filter == filter %>
<%= t("moderation.debates.index.filters.#{filter}") %>
<dd class="active"><%= t("moderation.debates.index.filters.#{filter}") %></dd>
<% else %>
<%= link_to t("moderation.debates.index.filters.#{filter}"),
moderation_debates_path(filter: filter) %>
<dd><%= link_to t("moderation.debates.index.filters.#{filter}"),
moderation_debates_path(filter: filter) %></dd>
<% end %>
<% end %>
</p>
</dl>
<h3><%= page_entries_info @debates %></h3>
<table>
<tr>
<th><%= t('moderation.debates.index.headers.flags') %></th>
<th><%= t('moderation.debates.index.headers.updated_at') %></th>
<th><%= t('moderation.debates.index.headers.title') %></th>
<th><%= t('moderation.debates.index.headers.description') %></th>
<th>
<%= t("moderation.debates.index.headers.title") %>&nbsp;|&nbsp;
<%= t("moderation.debates.index.headers.updated_at") %>&nbsp;|&nbsp;
<%= t("moderation.debates.index.headers.description") %>
</th>
<th class="text-center"><%= t("moderation.debates.index.headers.flags") %></th>
<th class="text-center" colspan="2"><%= t("moderation.debates.index.headers.actions") %></th>
</tr>
<% @debates.each do |debate| %>
<tr id="debate_<%= debate.id %>">
<td><%= debate.inappropiate_flags_count %></td>
<td><%= l debate.updated_at.to_date %></td>
<td><%= link_to debate.title, debate %></td>
<td><%= debate.description %></td>
<td>
<%= 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" %>
<br>
<span class="date"><%= l debate.updated_at.to_date %></span>
<br>
<%= debate.description %>
</td>
<% if can? :mark_as_reviewed, debate %>
<td class="text-center"><%= debate.inappropiate_flags_count %></td>
<td>
<%= link_to t("moderation.debates.index.hide"), hide_in_moderation_screen_moderation_debate_path(debate, request.query_parameters), method: :put, class: "delete" %>
</td>
<% if can? :archive, debate %>
<td>
<%= 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" %>
</td>
<% end %>
<% if debate.reviewed? %>
<td>
<%= t('moderation.debates.index.reviewed') %>
<% if debate.archived? %>
<td class="archived">
<%= t("moderation.debates.index.archived") %>
</td>
<% end %>
</tr>
@@ -45,4 +53,3 @@
</table>
<%= paginate @debates %>

View File

@@ -0,0 +1,15 @@
<div class="auth row">
<div class="small-12 medium-8 column small-centered">
<div class="panel">
<h2><%= t("devise_views.organizations.registrations.success.title") %></h2>
<p><%= t("devise_views.organizations.registrations.success.thank_you") %></p>
<p><%= t("devise_views.organizations.registrations.success.instructions_1_html") %></p>
<p><%= t("devise_views.organizations.registrations.success.instructions_2_html") %></p>
<p><%= t("devise_views.organizations.registrations.success.instructions_3_html") %></p>
<p>
<%= link_to t("devise_views.organizations.registrations.success.back_to_index"),
root_path, class: "button radius small margin-top" %>
</p>
</div>
</div>
</div>

View File

@@ -10,4 +10,4 @@
<%= link_to "#{debate.tags_count_out_of_limit(limit)}+", debate_path(debate) %>
<% end %>
</span>
<% end %>
<% end %>

View File

@@ -0,0 +1,13 @@
<div class="auth row">
<div class="small-12 medium-8 large-5 column small-centered">
<div class="panel">
<h1><%= t('omniauth.finish_signup.title') %></h1>
<%= 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 %>
</div>
</div>
</div>

View File

@@ -2,6 +2,9 @@
<div class="small-12 medium-8 large-5 column small-centered">
<div class="panel">
<h2><%= t("devise_views.users.registrations.new.title") %></h2>
<%= render 'devise/omniauth_form' %>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render 'shared/errors', resource: resource %>

View File

@@ -8,7 +8,7 @@
<h3><%= link_to featured_debate.title, featured_debate %></h3>
<p class="debate-info">
<i class="icon-comments"></i>&nbsp;
<%= 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") %>
</p>
<div class="debate-description">
<%= link_to featured_debate.description, featured_debate %>

View File

@@ -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) %>
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) %>

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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:"
other: "%{count} errores impidieron que este %{resource} fuera guardado:"

View File

@@ -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 <b>pending verification</b>."
instructions_1_html: "We will <b>contact you soon</b> in order to verify that you represent your collective."
instructions_2_html: "Meanwhile, <b>review your email</b>. We have sent you a <b>confirmation link to activate your account</b>."
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"

View File

@@ -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á <b>pendiente de verificación</b>."
instructions_1_html: "En breve <b>nos pondremos en contacto contigo</b> para verificar que realmente representas a este colectivo."
instructions_2_html: "Mientras <b>revisa tu correo electrónico</b>, te hemos enviado un <b>enlace para confirmar tu cuenta</b>."
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"

View File

@@ -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

View File

@@ -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

View File

@@ -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 <b<%{commenter}</b> on"
reply:
hi: "Hello, %{recipient}"
new_reply_by: "There'is a new reply by %{commenter} to your comment"
hi: Hello
title: New reply on your comment
new_reply_by_html: "There'is a new reply by <b>%{commenter}</b> to your comment on"

View File

@@ -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 <b>%{commenter}</b> en"
reply:
hi: "Hola, %{recipient}"
new_reply_by: "Hay una nueva respuesta de %{commenter} a tu comentario"
hi: Hola
title: Nueva respuesta a tu comentario
new_reply_by_html: "Hay una nueva respuesta de <b>%{commenter}</b> a tu comentario en"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,5 @@
class AddCommentsCountToDebate < ActiveRecord::Migration
def change
add_column :debates, :comments_count, :integer, default: 0
end
end

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
end

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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) }

View File

@@ -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 }

View File

@@ -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

View File

@@ -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

View File

@@ -22,3 +22,5 @@ RSpec.configure do |config|
end
Capybara.javascript_driver = :poltergeist
OmniAuth.config.test_mode = true

View File

@@ -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

View File

@@ -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