Merge branch 'master' into admin-77

This commit is contained in:
Juanjo Bazán
2015-08-08 13:00:41 +02:00
38 changed files with 628 additions and 92 deletions

1
.gitignore vendored
View File

@@ -19,5 +19,6 @@
/spec/examples.txt /spec/examples.txt
/config/database.yml /config/database.yml
/config/secrets.yml /config/secrets.yml
/config/deploy-secrets.yml
/coverage /coverage

View File

@@ -43,3 +43,5 @@ Cuando quieras resolver una incidencia mediante código:
* Lo que se esperaba que pasara * Lo que se esperaba que pasara
* Lo que ha pasado * Lo que ha pasado
* También es buena idea que incluyas tu sistema operativo, navegador, versión de navegador y plugins instalados. * También es buena idea que incluyas tu sistema operativo, navegador, versión de navegador y plugins instalados.
¡Gracias! :heart: :heart: :heart:

46
CONTRIBUTING_EN.md Normal file
View File

@@ -0,0 +1,46 @@
## Team members
* Raimond Garcia [github](https://github.com/voodoorai2000) | [twitter](https://twitter.com/voodoorai2000)
* Juanjo Bazán [github](https://github.com/xuanxu) | [twitter](https://twitter.com/xuanxu)
* Enrique García Cota [github](https://github.com/kikito) | [twitter](https://twitter.com/otikik)
* Alberto Garcia Cabeza [github](https://github.com/decabeza) | [twitter](https://twitter.com/decabeza)
## Report an issue
The prefered way to report any bug is [opening an issue in the project's Github repo](https://github.com/AyuntamientoMadrid/participacion/issues/new).
For more informal communication, contact team members via twitter
## Resolve an issue
Admins tag issues using two label related with collaboration availability:
* `PRs-welcome`: [issues labeled with PRs-welcome](https://github.com/AyuntamientoMadrid/participacion/labels/PRs-welcome) are well defined features ready to be implemented by whoever wants to do it.
* `Not-ready`: with this label admins mark features or changes that are not well defined yet or subject to an internal decision. Is not a good idea to start implementation of these isuues.
If you want to contribute code to solve an issue:
* Add a comment to tell everyone you are working on the issue.
* If an issue has someone assigned it means that person is already working on it.
* Fork the project.
* Create a topic branch based on master.
* Commit there your code to solve the issue.
* Make sure all test are passing (and add specs to test any new feature if needed).
* Open a *pull request* to the main repository describing what issue you are addressing.
## Other ways of contributing without coding
* If you think there's a feature missing, or find a bug, create an issue (make sure it has not already been reported).
* You can also help promoting the project talking about it in your social networks.
## How to report an issue
* Try to use a descriptive and to-the-point title
* Is a good idea to include some of there sections:
* Steps to reproduce the bug
* Expected behaviour/response
* Actual response
* Sometimes it is also helpful if you mention your operating system, browser version and installed plugins.
Thanks! :heart: :heart: :heart:

14
Capfile Normal file
View File

@@ -0,0 +1,14 @@
# Load DSL and set up stages
require 'capistrano/setup'
# Include default deployment tasks
require 'capistrano/deploy'
require 'capistrano/rvm'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano/passenger'
# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

15
Gemfile
View File

@@ -1,6 +1,5 @@
source 'https://rubygems.org' source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.3' gem 'rails', '4.2.3'
# Use PostgreSQL # Use PostgreSQL
@@ -26,11 +25,6 @@ gem 'devise'
# Use ActiveModel has_secure_password # Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7' # gem 'bcrypt', '~> 3.1.7'
gem 'acts_as_commentable_with_threading' gem 'acts_as_commentable_with_threading'
# Use Unicorn as the app server
# gem 'unicorn'
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development
gem 'acts-as-taggable-on' gem 'acts-as-taggable-on'
gem "responders" gem "responders"
gem 'foundation-rails' gem 'foundation-rails'
@@ -53,6 +47,11 @@ group :development, :test do
gem 'quiet_assets' gem 'quiet_assets'
gem 'letter_opener_web', '~> 1.2.0' gem 'letter_opener_web', '~> 1.2.0'
gem 'i18n-tasks' gem 'i18n-tasks'
gem 'capistrano', '3.4.0', require: false
gem "capistrano-bundler", '1.1.4', require: false
gem "capistrano-rails", '1.1.3', require: false
gem "capistrano-rvm", require: false
gem "capistrano-passenger", require: false
end end
group :test do group :test do
@@ -61,3 +60,7 @@ group :test do
gem 'coveralls', require: false gem 'coveralls', require: false
end end
group :test do
gem 'email_spec'
end

View File

@@ -54,6 +54,21 @@ GEM
byebug (5.0.0) byebug (5.0.0)
columnize (= 0.9.0) columnize (= 0.9.0)
cancancan (1.12.0) cancancan (1.12.0)
capistrano (3.4.0)
i18n
rake (>= 10.0.0)
sshkit (~> 1.3)
capistrano-bundler (1.1.4)
capistrano (~> 3.1)
sshkit (~> 1.2)
capistrano-passenger (0.1.1)
capistrano (~> 3.0)
capistrano-rails (1.1.3)
capistrano (~> 3.1)
capistrano-bundler (~> 1.1)
capistrano-rvm (0.1.2)
capistrano (~> 3.0)
sshkit (~> 1.2)
capybara (2.4.4) capybara (2.4.4)
mime-types (>= 1.16) mime-types (>= 1.16)
nokogiri (>= 1.3.3) nokogiri (>= 1.3.3)
@@ -75,6 +90,7 @@ GEM
coffee-script-source coffee-script-source
execjs execjs
coffee-script-source (1.9.1.1) coffee-script-source (1.9.1.1)
colorize (0.7.7)
columnize (0.9.0) columnize (0.9.0)
coveralls (0.8.2) coveralls (0.8.2)
json (~> 1.8) json (~> 1.8)
@@ -99,6 +115,9 @@ GEM
json json
thread thread
thread_safe thread_safe
email_spec (1.6.0)
launchy (~> 2.1)
mail (~> 2.2)
erubis (2.7.0) erubis (2.7.0)
execjs (2.5.2) execjs (2.5.2)
factory_girl (4.5.0) factory_girl (4.5.0)
@@ -146,6 +165,9 @@ GEM
mini_portile (0.6.2) mini_portile (0.6.2)
minitest (5.7.0) minitest (5.7.0)
multi_json (1.11.2) multi_json (1.11.2)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
net-ssh (2.9.2)
netrc (0.10.3) netrc (0.10.3)
nokogiri (1.6.6.2) nokogiri (1.6.6.2)
mini_portile (~> 0.6.0) mini_portile (~> 0.6.0)
@@ -233,6 +255,10 @@ GEM
actionpack (>= 3.0) actionpack (>= 3.0)
activesupport (>= 3.0) activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0) sprockets (>= 2.8, < 4.0)
sshkit (1.7.1)
colorize (>= 0.7.0)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
term-ansicolor (1.3.2) term-ansicolor (1.3.2)
tins (~> 1.0) tins (~> 1.0)
terminal-table (1.5.2) terminal-table (1.5.2)
@@ -273,12 +299,18 @@ DEPENDENCIES
acts_as_votable acts_as_votable
byebug byebug
cancancan cancancan
capistrano (= 3.4.0)
capistrano-bundler (= 1.1.4)
capistrano-passenger
capistrano-rails (= 1.1.3)
capistrano-rvm
capybara capybara
ckeditor ckeditor
coffee-rails (~> 4.1.0) coffee-rails (~> 4.1.0)
coveralls coveralls
database_cleaner database_cleaner
devise devise
email_spec
factory_girl_rails factory_girl_rails
foundation-rails foundation-rails
i18n-tasks i18n-tasks

View File

@@ -27,8 +27,8 @@ cd participacion
bundle install bundle install
cp config/database.yml.example config/database.yml cp config/database.yml.example config/database.yml
cp config/secrets.yml.example config/secrets.yml cp config/secrets.yml.example config/secrets.yml
bundle exec bin/rake db:create db:schema:load bundle exec bin/rake db:setup
RAILS_ENV=test bundle exec rake db:create db:schema:load RAILS_ENV=test bundle exec rake db:setup
``` ```
Para ejecutar la aplicación en local: Para ejecutar la aplicación en local:
@@ -47,4 +47,4 @@ El código de este proyecto está publicado bajo la licencia MIT (ver MIT-licens
## Contribuciones ## Contribuciones
Ver fichero CONTRIBUTING.md Ver fichero [CONTRIBUTING.md](CONTRIBUTING.md)

51
README_EN.md Normal file
View File

@@ -0,0 +1,51 @@
# Ayuntamiento de Madrid (Madrid city's government) eParticipation application
[![Build Status](https://travis-ci.org/AyuntamientoMadrid/participacion.svg?branch=master)](https://travis-ci.org/AyuntamientoMadrid/participacion)
[![Code Climate](https://codeclimate.com/github/AyuntamientoMadrid/participacion/badges/gpa.svg)](https://codeclimate.com/github/AyuntamientoMadrid/participacion)
[![Dependency Status](https://gemnasium.com/AyuntamientoMadrid/participacion.svg)](https://gemnasium.com/AyuntamientoMadrid/participacion)
[![Coverage Status](https://coveralls.io/repos/AyuntamientoMadrid/participacion/badge.svg?branch=master&service=github)](https://coveralls.io/github/AyuntamientoMadrid/participacion?branch=master)
This is the opensource code repository of Madrid City government eParticipation website
## Current state
Development started on [2015 July 15th](https://github.com/AyuntamientoMadrid/participacion/commit/8db36308379accd44b5de4f680a54c41a0cc6fc6)
The project is in its early stages. Features currently present in the code (and their names) are subject to change.
## Tech stack
The application backend is written in the [Ruby language](https://www.ruby-lang.org/) using the [Ruby on Rails](http://rubyonrails.org/) framework.
Frontend tools used include [SCSS](http://sass-lang.com/) over [Foundation](http://foundation.zurb.com/) for the styles.
## Configuration for development and test environments
Prerequisites: install git, Ruby 2.2.2, bundler gem and PostgreSQL.
```
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
```
Run the app locally:
```
bundle exec bin/rails s
```
Run the tests with:
```
bundle exec bin/rspec
```
## Licence
Code published under MIT license (see [MIT-license.md](MIT-license.md))
## Contributions
See [CONTRIBUTING_EN.md](CONTRIBUTING_EN.md)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 201 KiB

View File

@@ -96,7 +96,49 @@ header {
.button { .button {
color: white; color: white;
font-family: inherit; font-family: inherit;
margin-top: $line-height*2; margin-top: $line-height;
}
.home-page {
.button {
color: white;
font-family: inherit;
margin-top: $line-height*2;
}
}
.selected {
position: relative;
&:before {
top: -14px;
left: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
border-top-color: #fff;
border-width: 8px;
margin-left: -8px;
}
}
.language {
float: none;
text-align: center;
@media (min-width: 480px) {
float: left;
}
}
.external-links {
@extend .language;
@media (min-width: 480px) {
float: right;
}
} }
} }
@@ -105,13 +147,13 @@ header {
} }
.top-bar { .top-bar {
background: white; background: rgba(0,0,0,.5);
color: $header-color; color: white; //$header-color;
height: $line-height*4; height: $line-height*4;
max-width: 1170px !important; max-width: 1170px !important;
.name a { .name a {
color: black; color: white;
font-family: 'Lato'; font-family: 'Lato';
font-size: rem-calc(36); font-size: rem-calc(36);
font-weight: lighter; font-weight: lighter;
@@ -119,7 +161,7 @@ header {
padding-left: 0; padding-left: 0;
span { span {
color: $brand; // color: $brand;
font-size: rem-calc(24); font-size: rem-calc(24);
font-weight: normal; font-weight: normal;
} }
@@ -131,14 +173,29 @@ header {
} }
.top-bar-section { .top-bar-section {
margin-right: $line-height;
ul li > a {
font-size: rem-calc(14);
}
ul li, ul li:hover:not(.has-form) > a {
background: none;
}
li:not(.has-form) a:not(.button) { li:not(.has-form) a:not(.button) {
background: white; background: none;
color: $brand; color: white;
line-height: $line-height*4; line-height: $line-height*4;
&:hover {
background: none;
color: $link-hover;
}
} }
li.active:not(.has-form) a:not(.button) { li.active:not(.has-form) a:not(.button) {
background: none;
height: $line-height*4; height: $line-height*4;
line-height: $line-height*4; line-height: $line-height*4;
} }
@@ -147,9 +204,13 @@ header {
.top-links { .top-links {
color: white; color: white;
font-size: rem-calc(14); font-size: rem-calc(14);
height: $line-height*2; height: $line-height*3;
padding: $line-height/2 0; padding: $line-height/2 0;
@media (min-width: 480px) {
height: $line-height*2;
}
a { a {
color: white; color: white;
} }
@@ -179,7 +240,7 @@ header {
.icon-like { .icon-like {
background: white; background: white;
border: 2px solid white; border: 2px solid $votes-border;
border-radius: rem-calc(3); border-radius: rem-calc(3);
color: $votes-neutral; color: $votes-neutral;
display: inline-block; display: inline-block;
@@ -187,10 +248,10 @@ header {
line-height: rem-calc(30); line-height: rem-calc(30);
padding: rem-calc(3) rem-calc(6); padding: rem-calc(3) rem-calc(6);
position: relative; position: relative;
//when active => color: $votes-like;
&:hover { &:hover {
background: $votes-like; background: $votes-like;
border-color: white;
color: white; color: white;
cursor: pointer; cursor: pointer;
} }
@@ -202,7 +263,7 @@ header {
.icon-unlike { .icon-unlike {
background: white; background: white;
border: 2px solid white; border: 2px solid $votes-border;
border-radius: rem-calc(3); border-radius: rem-calc(3);
color: $votes-neutral; color: $votes-neutral;
display: inline-block; display: inline-block;
@@ -210,10 +271,10 @@ header {
line-height: rem-calc(30); line-height: rem-calc(30);
padding: rem-calc(3) rem-calc(6); padding: rem-calc(3) rem-calc(6);
position: relative; position: relative;
//when active => color: $votes-unlike;
&:hover { &:hover {
background: $votes-unlike; background: $votes-unlike;
border-color: white;
color: white; color: white;
cursor: pointer; cursor: pointer;
} }

View File

@@ -26,7 +26,8 @@ $comments-info: #A5B2B9;
$comments-text: #3F4549; $comments-text: #3F4549;
$header-color: #292B33; $header-color: #292B33;
$link: #0077B9; $link: #2895F1;
$link-hover: #2178BF;
$tags-bg: #FAFAFA; $tags-bg: #FAFAFA;
$tags-border: #F0F0F0; $tags-border: #F0F0F0;
@@ -37,8 +38,8 @@ $text-medium: #999999;
$text-light: #A3A6AD; $text-light: #A3A6AD;
$votes: #31708f; $votes: #31708f;
$votes-background: #0081B3; $votes-background: #26AEEE;//#0081B3;
$votes-border: #005b80; $votes-border: #1F94CB;//#005b80;
$votes-like: #7BD2A8; $votes-like: #7BD2A8;
$votes-like-act: #5D9E7F; $votes-like-act: #5D9E7F;
$votes-neutral: #CCCCCC; $votes-neutral: #CCCCCC;

View File

@@ -17,7 +17,7 @@ class AccountController < ApplicationController
end end
def account_params def account_params
params.require(:account).permit(:first_name, :last_name, :nickname, :use_nickname) params.require(:account).permit(:first_name, :last_name, :nickname, :use_nickname, :email_on_debate_comment, :email_on_comment_reply)
end end
end end

View File

@@ -7,6 +7,10 @@ class CommentsController < ApplicationController
@comment = Comment.build(@debate, current_user, params[:comment][:body]) @comment = Comment.build(@debate, current_user, params[:comment][:body])
@comment.save! @comment.save!
@comment.move_to_child_of(@parent) if reply? @comment.move_to_child_of(@parent) if reply?
Mailer.comment(@comment).deliver_now if email_on_debate_comment?
Mailer.reply(@comment).deliver_now if email_on_comment_reply?
respond_with @comment respond_with @comment
end end
@@ -32,4 +36,12 @@ class CommentsController < ApplicationController
def reply? def reply?
@parent.class == Comment @parent.class == Comment
end end
def email_on_debate_comment?
@comment.debate.author.email_on_debate_comment?
end
def email_on_comment_reply?
reply? && @parent.author.email_on_comment_reply?
end
end end

View File

@@ -0,0 +1,4 @@
class ApplicationMailer < ActionMailer::Base
default from: "participacion@madrid.es"
layout 'mailer'
end

16
app/mailers/mailer.rb Normal file
View File

@@ -0,0 +1,16 @@
class Mailer < ApplicationMailer
def comment(comment)
@comment = comment
@debate = comment.debate
mail(to: @debate.author.email, subject: t('mailer.comment.subject'))
end
def reply(reply)
@reply = reply
@debate = @reply.debate
parent = Comment.find(@reply.parent_id)
mail(to: parent.author.email, subject: t('mailer.reply.subject'))
end
end

View File

@@ -17,4 +17,13 @@ class Comment < ActiveRecord::Base
def self.find_parent(params) def self.find_parent(params)
params[:commentable_type].constantize.find(params[:commentable_id]) params[:commentable_type].constantize.find(params[:commentable_id])
end end
def debate
commentable if commentable.class == Debate
end
def author
user
end
end end

View File

@@ -15,6 +15,16 @@
<%= f.label :nickname, t("account.show.nickname_label") %> <%= f.label :nickname, t("account.show.nickname_label") %>
<%= f.text_field :nickname %> <%= f.text_field :nickname %>
<div>
<%= f.check_box :email_on_debate_comment %>
<%= f.label :email_on_debate_comment, t("account.show.email_on_debate_comment_label") %>
</div>
<div>
<%= f.check_box :email_on_comment_reply %>
<%= f.label :email_on_comment_reply, t("account.show.email_on_comment_reply_label") %>
</div>
<%= f.submit t("account.show.save_changes_submit"), class: "button radius" %> <%= f.submit t("account.show.save_changes_submit"), class: "button radius" %>
<% end %> <% end %>

View File

@@ -1,14 +1,17 @@
<ul class="right"> <ul class="right">
<% if user_signed_in? %> <% if user_signed_in? %>
<li> <li>
<%= link_to(t("devise_views.menu.login_items.logout"), destroy_user_session_path, method: :delete) %> <%= link_to(t("layouts.header.my_account_link"), account_path) %>
</li> </li>
<% else %> <li>
<li> <%= link_to(t("devise_views.menu.login_items.logout"), destroy_user_session_path, method: :delete) %>
<%= link_to(t("devise_views.menu.login_items.login"), new_user_session_path) %> </li>
</li> <% else %>
<li class="active"> <li>
<%= link_to(t("devise_views.menu.login_items.signup"), new_user_registration_path) %> <%= link_to(t("devise_views.menu.login_items.login"), new_user_session_path) %>
</li> </li>
<% end %> <li>
<%= link_to(t("devise_views.menu.login_items.signup"), new_user_registration_path, class: "button radius small") %>
</li>
<% end %>
</ul> </ul>

View File

@@ -1,53 +1,48 @@
<header class="<%= header_css %>"> <header class="<%= header_css %>">
<section class="top-links"> <section class="top-links">
<div class="row"> <div class="row">
<div class="small-12 column"> <div class="language">
<div class="right"> <span id="locale-switcher">
<a href="#"><%= t("layouts.header.external_link_transparency") %></a> | <a href="#"><%= t("layouts.header.external_link_opendata") %></a> <%= t("layouts.header.language") %>
| [
<span id="locale-switcher"> <% available_locales_to_switch.each do |locale| %>
[ <%= link_to(locale, params.merge(locale: locale), id: "locale-link-#{locale}") %>
<% available_locales_to_switch.each do |locale| %> <% end %>
<%= link_to(locale, params.merge(locale: locale), id: "locale-link-#{locale}") %> ]
<% end %> </div>
] <div class="external-links">
</span> <%= link_to t("layouts.header.participation"), root_path, class: "selected" %>&nbsp;|&nbsp;
</div> <a href="#"><%= t("layouts.header.external_link_transparency") %></a>&nbsp;|&nbsp;
</div> <a href="#"><%= t("layouts.header.external_link_opendata") %></a>
</div> </div>
</section> </div>
</section>
<div class="contain-to-grid"> <div class="contain-to-grid clear">
<nav class="top-bar" data-topbar role="navigation"> <nav class="top-bar" data-topbar role="navigation">
<ul class="title-area"> <ul class="title-area">
<li class="name"> <li class="name">
<%= link_to root_path do %> <%= link_to root_path do %>
<%= image_tag('header_logo_madrid.png', class: 'left', size: '96x96') %> <%= image_tag('header_logo_madrid.png', class: 'left', size: '96x96') %>
<%= t("layouts.header.open_gov", open: "<strong>#{t('layouts.header.open')}</strong>").html_safe %> | <span><%= t("layouts.header.participation") %></span> <%= t("layouts.header.open_gov", open: "<strong>#{t('layouts.header.open')}</strong>").html_safe %> | <span><%= t("layouts.header.participation") %></span>
<% end %> <% end %>
</li> </li>
<li class="toggle-topbar menu-icon"><a href="#"><span><%= t("layouts.header.menu") %></span></a></li> <li class="toggle-topbar menu-icon"><a href="#"><span><%= t("layouts.header.menu") %></span></a></li>
</ul> </ul>
<section class="top-bar-section"> <section class="top-bar-section">
<%= render 'devise/menu/login_items' %> <%= render 'devise/menu/login_items' %>
</section>
</nav>
</div>
<% if user_signed_in? %> <% if home_page? %>
<ul class="right"> <div class="row home-page">
<li><%= link_to(t("layouts.header.my_account_link"), account_path) %></li> <div class="small-12 column text-center">
</ul> <h1><%= t("layouts.header.open_city") %></h1>
<% end %> <h2><%= t("layouts.header.open_city_slogan") %></h2>
</section> <%= link_to t("layouts.header.create_debate"), new_debate_path, class: 'button radius' %>
</nav> </div>
</div> </div>
<% end %>
<% if home_page? %>
<div class="row">
<div class="small-12 column text-center">
<h1><%= t("layouts.header.open_city") %></h1>
<h2><%= t("layouts.header.open_city_slogan") %></h2>
<%= link_to t("layouts.header.create_debate"), new_debate_path, class: 'button radius' %>
</div>
</div>
<% end %>
</header> </header>

View File

@@ -0,0 +1,5 @@
<html>
<body>
<%= yield %>
</body>
</html>

View File

@@ -0,0 +1,7 @@
Hello,
<div><%= @comment.author.name %></div>
<div><%= @comment.body %></div>
<div><%= link_to @debate.title, debate_url(@debate) %></div>

View File

@@ -0,0 +1,7 @@
Hello,
<div><%= @reply.author.name %></div>
<div><%= @reply.body %></div>
<div><%= link_to @debate.title, debate_url(@debate) %></div>

View File

@@ -0,0 +1,18 @@
staging:
deploy_to: "/var/www/participacion"
ssh_port: 21
server: staging.participacion.madrid.es
user: xxxxx
preproduction:
deploy_to: "/var/www/participacion"
ssh_port: 2222
server: xxx.xxx.xxx.xxx
user: xxxxx
production:
deploy_to: "/var/www/participacion"
ssh_port: 2222
server: xxx.xxx.xxx.xxx
user: xxxxx

38
config/deploy.rb Normal file
View File

@@ -0,0 +1,38 @@
# config valid only for current version of Capistrano
lock '3.4.0'
def deploysecret(key)
@deploy_secrets_yml ||= YAML.load_file('config/deploy-secrets.yml')[fetch(:stage).to_s]
@deploy_secrets_yml[key.to_s]
end
set :rails_env, fetch(:stage)
set :rvm_ruby_version, '2.2.2'
set :application, 'participacion'
set :repo_url, 'git@github.com:AyuntamientoMadrid/participacion.git'
set :scm, :git
set :revision, `git rev-parse --short #{fetch(:branch)}`.strip
set :log_level, :info
set :linked_files, %w{config/database.yml config/secrets.yml}
set :linked_dirs, %w{log tmp public/system public/assets}
set :keep_releases, 5
set :local_user, ENV['USER']
namespace :deploy do
after :restart, :clear_cache do
on roles(:web), in: :groups, limit: 3, wait: 10 do
# Here we can do anything such as:
# within release_path do
# execute :rake, 'cache:clear'
# end
end
end
end

View File

@@ -0,0 +1,5 @@
set :deploy_to, deploysecret(:deploy_to)
set :branch, :production
set :ssh_options, port: deploysecret(:ssh_port)
server deploysecret(:server), user: deploysecret(:user), roles: %w(web app db importer)

View File

@@ -0,0 +1,5 @@
set :deploy_to, deploysecret(:deploy_to)
set :branch, :production
set :ssh_options, port: deploysecret(:ssh_port)
server deploysecret(:server), user: deploysecret(:user), roles: %w(web app db importer)

7
config/deploy/staging.rb Normal file
View File

@@ -0,0 +1,7 @@
set :deploy_to, deploysecret(:deploy_to)
set :branch, :master
set :ssh_options, port: deploysecret(:ssh_port)
set :passenger_restart_with_sudo, false
server deploysecret(:server), user: deploysecret(:user), roles: %w(web app db importer)

View File

@@ -11,6 +11,7 @@ en:
open_city_slogan: So the citizens can decide what kind of city they want. open_city_slogan: So the citizens can decide what kind of city they want.
create_debate: Create a debate create_debate: Create a debate
my_account_link: My account my_account_link: My account
language: Site language
admin: admin:
dashboard: dashboard:
index: index:
@@ -70,6 +71,8 @@ en:
show: show:
title: "My account" title: "My account"
save_changes_submit: "Save changes" save_changes_submit: "Save changes"
email_on_debate_comment_label: "Receive email when someone comments on my debates"
email_on_comment_reply_label: "Receive email when someone replies to my comments"
change_credentials_link: "Change my credentials" change_credentials_link: "Change my credentials"
first_name_label: "First Name" first_name_label: "First Name"
last_name_label: "Last Name" last_name_label: "Last Name"
@@ -81,3 +84,8 @@ en:
shared: shared:
tags_cloud: tags_cloud:
tags: Tags tags: Tags
mailer:
comment:
subject: Someone has commented on your debate
reply:
subject: Someone has replied to your comment

View File

@@ -11,6 +11,7 @@ es:
open_city_slogan: Para que todos los madrileños decidamos que ciudad queremos tener. open_city_slogan: Para que todos los madrileños decidamos que ciudad queremos tener.
create_debate: Crea un debate create_debate: Crea un debate
my_account_link: Mi cuenta my_account_link: Mi cuenta
language: Idioma de la página
admin: admin:
dashboard: dashboard:
index: index:
@@ -70,6 +71,8 @@ es:
show: show:
title: "Mi cuenta" title: "Mi cuenta"
save_changes_submit: "Guardar cambios" save_changes_submit: "Guardar cambios"
email_on_debate_comment_label: "Recibir un email cuando alguien commenta en mis debates"
email_on_comment_reply_label: "Recibir un email cuando alguien contesta a mis comentarios"
change_credentials_link: "Cambiar mi contraseña" change_credentials_link: "Cambiar mi contraseña"
first_name_label: "Nombre" first_name_label: "Nombre"
last_name_label: "Apellidos" last_name_label: "Apellidos"
@@ -81,4 +84,8 @@ es:
shared: shared:
tags_cloud: tags_cloud:
tags: Etiquetas tags: Etiquetas
mailer:
comment:
subject: Alguien ha comentado en tu debate
reply:
subject: Alguien ha respondido a tu comentario

View File

@@ -0,0 +1,6 @@
class AddPreferencesToUsers < ActiveRecord::Migration
def change
add_column :users, :email_on_debate_comment, :boolean, default: false
add_column :users, :email_on_comment_reply, :boolean, default: false
end
end

View File

@@ -94,6 +94,8 @@ ActiveRecord::Schema.define(version: 20150807140346) do
t.string "unconfirmed_email" t.string "unconfirmed_email"
t.string "nickname" t.string "nickname"
t.boolean "use_nickname", default: false, null: false t.boolean "use_nickname", default: false, null: false
t.boolean "email_on_debate_comment", default: false
t.boolean "email_on_comment_reply", default: false
end end
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree

View File

@@ -21,6 +21,8 @@ feature 'Account' do
fill_in 'account_first_name', with: 'Larry' fill_in 'account_first_name', with: 'Larry'
fill_in 'account_last_name', with: 'Bird' fill_in 'account_last_name', with: 'Bird'
check 'account_email_on_debate_comment'
check 'account_email_on_comment_reply'
click_button 'Save changes' click_button 'Save changes'
expect(page).to have_content "Saved" expect(page).to have_content "Saved"
@@ -29,5 +31,7 @@ feature 'Account' do
expect(page).to have_selector("input[value='Larry']") expect(page).to have_selector("input[value='Larry']")
expect(page).to have_selector("input[value='Bird']") expect(page).to have_selector("input[value='Bird']")
expect(page).to have_selector("input[id='account_email_on_debate_comment'][value='1']")
expect(page).to have_selector("input[id='account_email_on_comment_reply'][value='1']")
end end
end end

View File

@@ -41,11 +41,11 @@ feature 'Comments' do
login_as(user) login_as(user)
visit debate_path(debate) visit debate_path(debate)
fill_in 'comment_body', with: '¿Has pensado en esto...?' fill_in 'comment_body', with: 'Have you thought about...?'
click_button 'Publish comment' click_button 'Publish comment'
within "#comments" do within "#comments" do
expect(page).to have_content '¿Has pensado en esto...?' expect(page).to have_content 'Have you thought about...?'
end end
end end
@@ -60,12 +60,12 @@ feature 'Comments' do
click_link "Reply" click_link "Reply"
within "#js-comment-form-comment_#{comment.id}" do within "#js-comment-form-comment_#{comment.id}" do
fill_in 'comment_body', with: 'La semana que viene está hecho.' fill_in 'comment_body', with: 'It will be done next week.'
click_button 'Publish reply' click_button 'Publish reply'
end end
within "#comment-#{comment.id}" do within "#comment-#{comment.id}" do
expect(page).to have_content 'La semana que viene está hecho.' expect(page).to have_content 'It will be done next week.'
end end
end end

View File

@@ -0,0 +1,63 @@
require 'rails_helper'
feature 'Emails' do
background do
reset_mailer
end
scenario "Signup Email" do
sign_up
email = open_last_email
expect(email).to have_subject('Confirmation instructions')
expect(email).to deliver_to('manuela@madrid.es')
expect(email).to have_body_text(user_confirmation_path)
end
scenario "Reset password" do
reset_password
email = open_last_email
expect(email).to have_subject('Reset password instructions')
expect(email).to deliver_to('manuela@madrid.es')
expect(email).to have_body_text(edit_user_password_path)
end
scenario "Debate comment", :js do
user = create(:user, email_on_debate_comment: true)
debate = create(:debate, author: user)
comment_on(debate)
email = open_last_email
expect(email).to have_subject('Someone has commented on your debate')
expect(email).to deliver_to(debate.author)
expect(email).to have_body_text(debate_path(debate))
end
scenario "Comment reply", :js do
user = create(:user, email_on_comment_reply: true)
reply_to(user)
email = open_last_email
expect(email).to have_subject('Someone has replied to your comment')
expect(email).to deliver_to(user)
expect(email).to have_body_text(debate_path(Comment.first.debate))
end
scenario 'Do not send email about debate comment unless set in preferences', :js do
user = create(:user, email_on_debate_comment: false)
debate = create(:debate, author: user)
comment_on(debate)
expect { open_last_email }.to raise_error "No email has been sent!"
end
scenario "Do not send email about comment reply unless set in preferences", :js do
user = create(:user, email_on_comment_reply: false)
reply_to(user)
expect { open_last_email }.to raise_error "No email has been sent!"
end
end

View File

@@ -44,4 +44,26 @@ feature 'Users' do
expect(page).to have_content 'Signed out successfully.' expect(page).to have_content 'Signed out successfully.'
end end
scenario 'Reset password' do
create(:user, email: 'manuela@madrid.es')
visit '/'
click_link 'Log in'
click_link 'Forgot your password?'
fill_in 'user_email', with: 'manuela@madrid.es'
click_button 'Send me reset password instructions'
expect(page).to have_content "You will receive an email with instructions on how to reset your password in a few minutes."
sent_token = /.*reset_password_token=(.*)".*/.match(ActionMailer::Base.deliveries.last.body.to_s)[1]
visit edit_user_password_path(reset_password_token: sent_token)
fill_in 'user_password', with: 'new password'
fill_in 'user_password_confirmation', with: 'new password'
click_button 'Change my password'
expect(page).to have_content "Your password has been changed successfully. You are now signed in."
end
end end

View File

@@ -34,6 +34,20 @@ describe User do
expect(subject).to be_valid expect(subject).to be_valid
end end
describe 'preferences' do
describe 'email_on_debate_comment' do
it 'should be false by default' do
expect(subject.email_on_debate_comment).to eq(false)
end
end
describe 'email_on_comment_reply' do
it 'should be false by default' do
expect(subject.email_on_comment_reply).to eq(false)
end
end
end
describe 'use_nickname' do describe 'use_nickname' do
describe 'when true' do describe 'when true' do
before { subject.use_nickname = true } before { subject.use_nickname = true }

View File

@@ -1,5 +1,7 @@
require 'factory_girl_rails' require 'factory_girl_rails'
require 'database_cleaner' require 'database_cleaner'
require "email_spec"
Dir["./spec/support/**/*.rb"].sort.each { |f| require f}
RSpec.configure do |config| RSpec.configure do |config|
config.use_transactional_fixtures = false config.use_transactional_fixtures = false
@@ -7,7 +9,9 @@ RSpec.configure do |config|
config.filter_run :focus config.filter_run :focus
config.run_all_when_everything_filtered = true config.run_all_when_everything_filtered = true
config.include FactoryGirl::Syntax::Methods config.include FactoryGirl::Syntax::Methods
config.include(EmailSpec::Helpers)
config.include(EmailSpec::Matchers)
config.include(CommonActions)
config.before(:suite) do config.before(:suite) do
DatabaseCleaner.clean_with :truncation DatabaseCleaner.clean_with :truncation
end end

View File

@@ -0,0 +1,54 @@
module CommonActions
def sign_up
visit '/'
click_link 'Sign up'
fill_in 'user_first_name', with: 'Manuela'
fill_in 'user_last_name', with: 'Carmena'
fill_in 'user_email', with: 'manuela@madrid.es'
fill_in 'user_password', with: 'judgementday'
fill_in 'user_password_confirmation', with: 'judgementday'
click_button 'Sign up'
end
def reset_password
create(:user, email: 'manuela@madrid.es')
visit '/'
click_link 'Log in'
click_link 'Forgot your password?'
fill_in 'user_email', with: 'manuela@madrid.es'
click_button 'Send me reset password instructions'
end
def comment_on(debate)
user2 = create(:user)
login_as(user2)
visit debate_path(debate)
fill_in 'comment_body', with: 'Have you thought about...?'
click_button 'Publish comment'
expect(page).to have_content 'Have you thought about...?'
end
def reply_to(user)
manuela = create(:user)
debate = create(:debate)
comment = create(:comment, commentable: debate, user: user)
login_as(manuela)
visit debate_path(debate)
click_link "Reply"
within "#js-comment-form-comment_#{comment.id}" do
fill_in 'comment_body', with: 'It will be done next week.'
click_button 'Publish reply'
end
expect(page).to have_content 'It will be done next week.'
end
end