diff --git a/.rspec b/.rspec
index 4e1e0d2f7..f26ef5abe 100644
--- a/.rspec
+++ b/.rspec
@@ -1 +1,2 @@
--color
+
diff --git a/.travis.yml b/.travis.yml
index c1d4bc930..cb294ec9c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,6 @@
language: ruby
+addons:
+ postgresql: "9.4"
rvm:
- "2.2.2"
cache: bundler
diff --git a/Gemfile b/Gemfile
index a4e9b0e20..de35b0b26 100644
--- a/Gemfile
+++ b/Gemfile
@@ -34,6 +34,10 @@ gem 'cancancan'
gem 'social-share-button'
gem 'initialjs-rails'
gem 'unicorn'
+gem 'paranoia'
+
+gem 'ahoy_matey', '~> 1.2.1'
+gem 'groupdate' # group temporary data
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
@@ -45,6 +49,7 @@ group :development, :test do
gem 'rspec-rails', '~> 3.0'
gem 'capybara'
gem 'factory_girl_rails'
+ gem 'fuubar'
gem 'launchy'
gem 'quiet_assets'
gem 'letter_opener_web', '~> 1.2.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 2bcab8ad0..2753c16ba 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -44,12 +44,23 @@ GEM
awesome_nested_set (>= 3.0)
acts_as_votable (0.10.0)
addressable (2.3.8)
+ ahoy_matey (1.2.1)
+ addressable
+ browser (>= 0.4.0)
+ errbase
+ geocoder
+ rails
+ referer-parser (>= 0.3.0)
+ request_store
+ user_agent_parser
+ uuidtools
arel (6.0.3)
awesome_nested_set (3.0.2)
activerecord (>= 4.0.0, < 5)
bcrypt (3.1.10)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
+ browser (0.9.1)
builder (3.2.2)
byebug (5.0.0)
columnize (= 0.9.0)
@@ -116,6 +127,7 @@ GEM
email_spec (1.6.0)
launchy (~> 2.1)
mail (~> 2.2)
+ errbase (0.0.3)
erubis (2.7.0)
execjs (2.5.2)
factory_girl (4.5.0)
@@ -132,8 +144,14 @@ GEM
activesupport (~> 4.1, >= 4.1.1)
railties (~> 4.1, >= 4.1.1)
tzinfo (~> 1.2, >= 1.2.2)
+ fuubar (2.0.0)
+ rspec (~> 3.0)
+ ruby-progressbar (~> 1.4)
+ geocoder (1.2.9)
globalid (0.3.6)
activesupport (>= 4.1.0)
+ groupdate (2.4.0)
+ activesupport (>= 3)
highline (1.7.3)
http-cookie (1.0.2)
domain_name (~> 0.5)
@@ -179,6 +197,8 @@ GEM
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
orm_adapter (0.5.0)
+ paranoia (2.1.3)
+ activerecord (~> 4.0)
pg (0.18.2)
poltergeist (1.6.0)
capybara (~> 2.1)
@@ -216,12 +236,18 @@ GEM
thor (>= 0.18.1, < 2.0)
raindrops (0.15.0)
rake (10.4.2)
+ referer-parser (0.3.0)
+ request_store (1.2.0)
responders (2.1.0)
railties (>= 4.2.0, < 5)
rest-client (1.8.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 3.0)
netrc (~> 0.7)
+ rspec (3.3.0)
+ rspec-core (~> 3.3.0)
+ rspec-expectations (~> 3.3.0)
+ rspec-mocks (~> 3.3.0)
rspec-core (3.3.2)
rspec-support (~> 3.3.0)
rspec-expectations (3.3.1)
@@ -239,6 +265,7 @@ GEM
rspec-mocks (~> 3.3.0)
rspec-support (~> 3.3.0)
rspec-support (3.3.0)
+ ruby-progressbar (1.7.5)
sass (3.4.16)
sass-rails (5.0.3)
railties (>= 4.0.0, < 5.0)
@@ -289,6 +316,8 @@ GEM
kgio (~> 2.6)
rack
raindrops (~> 0.7)
+ user_agent_parser (2.2.0)
+ uuidtools (2.1.5)
warden (1.2.3)
rack (>= 1.0)
web-console (2.2.1)
@@ -309,6 +338,7 @@ DEPENDENCIES
acts-as-taggable-on
acts_as_commentable_with_threading
acts_as_votable
+ ahoy_matey (~> 1.2.1)
byebug
cancancan
capistrano (= 3.4.0)
@@ -325,12 +355,15 @@ DEPENDENCIES
factory_girl_rails
foundation-rails
foundation_rails_helper
+ fuubar
+ groupdate
i18n-tasks
initialjs-rails
jquery-rails
kaminari
launchy
letter_opener_web (~> 1.2.0)
+ paranoia
pg
poltergeist
quiet_assets
diff --git a/README.md b/README.md
index 1d8ef040d..9fe47f6ad 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ Las herramientas utilizadas para el frontend no están cerradas aún. Los estilo
## Configuración para desarrollo y tests
-Prerequisitos: tener instalado git, ImageMagick, Ruby 2.2.2, la gema `bundler`, y una librería moderna de PostgreSQL.
+Prerequisitos: tener instalado git, ImageMagick, Ruby 2.2.2, la gema `bundler`, y PostgreSQL (9.4 o superior).
```
cd participacion
diff --git a/README_EN.md b/README_EN.md
index e43be2875..40a39ae01 100644
--- a/README_EN.md
+++ b/README_EN.md
@@ -21,7 +21,7 @@ Frontend tools used include [SCSS](http://sass-lang.com/) over [Foundation](http
## Configuration for development and test environments
-Prerequisites: install git, ImageMagick, Ruby 2.2.2, bundler gem and PostgreSQL.
+Prerequisites: install git, ImageMagick, Ruby 2.2.2, bundler gem and PostgreSQL (>=9.4).
```
cd participacion
diff --git a/app/assets/fonts/icons.eot b/app/assets/fonts/icons.eot
index 166eca82e..8168c0ec4 100644
Binary files a/app/assets/fonts/icons.eot and b/app/assets/fonts/icons.eot differ
diff --git a/app/assets/fonts/icons.svg b/app/assets/fonts/icons.svg
index 498eb27a7..70349fe9c 100644
--- a/app/assets/fonts/icons.svg
+++ b/app/assets/fonts/icons.svg
@@ -14,11 +14,15 @@
-
+
+
+
+
+
diff --git a/app/assets/fonts/icons.ttf b/app/assets/fonts/icons.ttf
index 285caed39..876fc7567 100644
Binary files a/app/assets/fonts/icons.ttf and b/app/assets/fonts/icons.ttf differ
diff --git a/app/assets/fonts/icons.woff b/app/assets/fonts/icons.woff
index 02c11f23e..8590e1587 100644
Binary files a/app/assets/fonts/icons.woff and b/app/assets/fonts/icons.woff differ
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 11bbe4cad..e630af974 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -17,6 +17,10 @@
//= require ckeditor/init
//= require social-share-button
//= require initial
+//= require ahoy
+//= require d3
+//= require c3
+//= require c3ext
//= require app
//= require_tree .
@@ -25,6 +29,7 @@ var initialize_modules = function() {
App.Users.initialize();
App.Votes.initialize();
App.Tags.initialize();
+ App.Stats.initialize();
};
$(function(){
diff --git a/app/assets/javascripts/comments.js.coffee b/app/assets/javascripts/comments.js.coffee
index 377fa4d1a..8a9ebe0b1 100644
--- a/app/assets/javascripts/comments.js.coffee
+++ b/app/assets/javascripts/comments.js.coffee
@@ -1,8 +1,11 @@
App.Comments =
- add_response: (parent_id, response_html) ->
+ add_comment: (parent_id, response_html) ->
$(response_html).insertAfter($("#js-comment-form-#{parent_id}"))
+ add_reply: (parent_id, response_html) ->
+ $("##{parent_id} .comment-children:first").prepend($(response_html))
+
display_error: (field_with_errors, error_html) ->
$(error_html).insertAfter($("#{field_with_errors}"))
diff --git a/app/assets/javascripts/moderator_comment.js.coffee b/app/assets/javascripts/moderator_comment.js.coffee
new file mode 100644
index 000000000..7cc680169
--- /dev/null
+++ b/app/assets/javascripts/moderator_comment.js.coffee
@@ -0,0 +1,7 @@
+App.ModeratorComments =
+
+ add_class_faded: (id) ->
+ $("##{id} .comment-body:first").addClass("faded")
+
+ hide_moderator_actions: (id) ->
+ $("##{id} #moderator-comment-actions:first").hide()
\ No newline at end of file
diff --git a/app/assets/javascripts/moderator_debates.js.coffee b/app/assets/javascripts/moderator_debates.js.coffee
new file mode 100644
index 000000000..802504ec2
--- /dev/null
+++ b/app/assets/javascripts/moderator_debates.js.coffee
@@ -0,0 +1,8 @@
+App.ModeratorDebates =
+
+ add_class_faded: (id) ->
+ $("##{id}").addClass("faded")
+ $("#comments").addClass("faded")
+
+ hide_moderator_actions: (id) ->
+ $("##{id} #moderator-debate-actions:first").hide()
\ No newline at end of file
diff --git a/app/assets/javascripts/stats.js.coffee b/app/assets/javascripts/stats.js.coffee
new file mode 100644
index 000000000..7fcdfb00a
--- /dev/null
+++ b/app/assets/javascripts/stats.js.coffee
@@ -0,0 +1,11 @@
+# Helper for generate C3.js graphs
+#----------------------------------------------------------------------
+
+buildGraph = (el) ->
+ url = $(el).data 'graph'
+ conf = bindto: el, data: {x: 'x', url: url, mimeType: 'json'}, axis: { x: {type: 'timeseries',tick: { format: '%Y-%m-%d' } }}
+ graph = c3.generate conf
+
+App.Stats =
+ initialize: ->
+ buildGraph(g) for g in $("[data-graph]")
diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss
new file mode 100644
index 000000000..bf9d7dd22
--- /dev/null
+++ b/app/assets/stylesheets/admin.scss
@@ -0,0 +1,169 @@
+// Table of Contents
+//
+// 01. Global styles
+// 02. Sidebar
+// 03. List elements
+// 04. Stats
+//
+
+// 01. Global styles
+// - - - - - - - - - - - - - - - - - - - - - - - - -
+
+body.admin {
+ background: white;
+
+ h2 {
+ font-size: rem-calc(24);
+ font-weight: bold;
+ }
+
+ h3 {
+ font-size: rem-calc(14);
+ font-weight: normal;
+ }
+
+ form {
+ .button {
+ margin-top: 0;
+ }
+ }
+
+ .button.secondary {
+ margin-right: rem-calc(12);
+ }
+
+ .admin-content {
+ margin-top: rem-calc(24);
+ }
+
+ .is-featured {
+ margin-top: rem-calc(36);
+ }
+}
+
+// 02. Sidebar
+// - - - - - - - - - - - - - - - - - - - - - - - - -
+
+.admin-sidebar {
+ margin-left: rem-calc(-15);
+ margin-top: rem-calc(-48);
+
+ ul {
+ list-style-type: none;
+ margin-left: 0;
+ padding: 0;
+
+ [class^="icon-"] {
+ display: inline-block;
+ font-size: rem-calc(24);
+ padding-right: rem-calc(24);
+ padding-top: rem-calc(4);
+ }
+
+ li {
+ background: #2E343F;
+ border-bottom: 1px solid #292f39;
+ border-top: 1px solid #353c49;
+ margin: 0;
+ outline: 0;
+
+ &:first-child {
+ background: #2B3139;
+ color: rgba(255,255,255,0.3);
+ padding: rem-calc(24) rem-calc(12);
+ text-transform: uppercase;
+ }
+
+ &.active{
+ background: #373D47;
+
+ a:not(.button) {
+ color: white;
+ }
+ }
+ }
+
+ li a:not(.button) {
+ color: rgba(255,255,255,0.3);
+ line-height: rem-calc(48);
+ padding-left: rem-calc(12);
+ vertical-align: top;
+
+ &:hover {
+ color: white;
+ }
+ }
+ }
+}
+
+// 03. List elements
+// - - - - - - - - - - - - - - - - - - - - - - - - -
+
+.admin-list {
+ list-style-type: none;
+ margin: 0;
+ margin-bottom: rem-calc(48);
+
+ form {
+ clear: both;
+
+ .checkbox {
+ font-size: rem-calc(12);
+ }
+ }
+
+ li {
+ border-bottom: 1px solid #E7E9EC;
+ font-size: rem-calc(14);
+ min-height: rem-calc(72);
+ padding: rem-calc(12);
+
+ &:first-child {
+ border-top: 1px solid #E7E9EC;
+ }
+
+ &:nth-child(odd) {
+ background: #F0F2F6;
+ }
+ }
+
+ .tag {
+ float: left;
+ font-size: rem-calc(18);
+ padding: 0;
+ }
+
+ .button {
+ margin: 0;
+ }
+}
+
+.delete {
+ border-bottom: 1px dotted #CF2A0E;
+ color: #F04124;
+ font-size: rem-calc(12);
+
+ &:hover, &:active, &:focus {
+ border: 0;
+ color: #cf2a0e;
+ }
+}
+
+.level {
+ font-size: rem-calc(12);
+}
+
+.official {
+ background-color: #e7e7e7;
+ border-radius: rem-calc(3);
+ font-size: rem-calc(12);
+ font-weight: normal;
+ padding: rem-calc(6) rem-calc(12);
+}
+
+// 04. Stats
+// - - - - - - - - - - - - - - - - - - - - - - - - -
+
+.stats {
+ background: white;
+}
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index e4379397e..48bfdc7b4 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -6,5 +6,7 @@
@import "fonts";
@import "icons";
@import "variables";
+@import "admin";
@import "participacion";
@import "debates";
+@import "c3";
diff --git a/app/assets/stylesheets/debates.scss b/app/assets/stylesheets/debates.scss
index f242e8757..387e2e453 100644
--- a/app/assets/stylesheets/debates.scss
+++ b/app/assets/stylesheets/debates.scss
@@ -138,10 +138,6 @@
// 02. Index
// - - - - - - - - - - - - - - - - - - - - - - - - -
-.featured-debates {
- margin-top: rem-calc(23);
-}
-
.debate-featured {
.panel {
@@ -244,7 +240,6 @@
.debates-list {
margin-bottom: rem-calc(48);
- margin-top: rem-calc(24);
}
.debate {
@@ -371,10 +366,6 @@
color: $text-medium;
}
- .bullet {
- color: $border;
- }
-
p {
font-size: rem-calc(14);
line-height: $line-height;
@@ -436,6 +427,10 @@
}
}
+.bullet {
+ color: $border;
+}
+
// 04. New
// - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -571,4 +566,9 @@
}
}
}
+
+}
+
+.faded {
+ opacity: 0.4;
}
diff --git a/app/assets/stylesheets/icons.scss b/app/assets/stylesheets/icons.scss
index cfebe4e83..4d131e589 100644
--- a/app/assets/stylesheets/icons.scss
+++ b/app/assets/stylesheets/icons.scss
@@ -58,9 +58,6 @@
.icon-calendar:before {
content: "g";
}
-.icon-lightbulb:before {
- content: "h";
-}
.icon-comment-quotes:before {
content: "i";
}
@@ -79,3 +76,18 @@
.icon-star:before {
content: "n";
}
+.icon-eye:before {
+ content: "p";
+}
+.icon-user:before {
+ content: "o";
+}
+.icon-settings:before {
+ content: "q";
+}
+.icon-stats:before {
+ content: "r";
+}
+.icon-initiatives:before {
+ content: "h";
+}
diff --git a/app/assets/stylesheets/participacion.scss b/app/assets/stylesheets/participacion.scss
index 6e5ad3d7b..13ecb93c3 100644
--- a/app/assets/stylesheets/participacion.scss
+++ b/app/assets/stylesheets/participacion.scss
@@ -10,6 +10,8 @@
// 08. Forms
// 09. Alerts
// 10. User account
+// 11. Filters
+// 12. Official levels
//
// 01. Variables
@@ -111,7 +113,6 @@ h1, h2, h3, h4, h5, h6 {
}
.sidebar {
- margin-top: rem-calc(24);
margin-bottom: rem-calc(48);
}
@@ -134,7 +135,7 @@ header {
min-height: rem-calc(480);
&.results {
- min-height: rem-calc(192);
+ min-height: rem-calc(216);
}
h1 {
@@ -276,6 +277,35 @@ header {
}
}
+.subnavigation {
+ background: white;
+ border-bottom: 1px solid white;
+ clear: both;
+
+ a {
+ color: $link;
+ font-size: rem-calc(14);
+ font-weight: bold;
+
+ &.active {
+ color: $text;
+
+ &:after {
+ bottom: -17px;
+ left: 50%;
+ border: solid transparent;
+ content: " ";
+ height: 0;
+ width: 0;
+ position: absolute;
+ border-top-color: #fff;
+ border-width: 8px;
+ margin-left: -8px;
+ }
+ }
+ }
+}
+
// 05. Footer
// - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -556,3 +586,63 @@ form {
}
}
}
+
+// 11. Filters
+// - - - - - - - - - - - - - - - - - - - - - - - - -
+
+.filters {
+
+ h2 {
+ display: inline-block;
+ font-size: rem-calc(24);
+ margin: rem-calc(24) 0;
+ }
+
+ select {
+ height: auto;
+ margin: rem-calc(24) rem-calc(6);
+ min-width: rem-calc(180);
+ outline: 0;
+ padding: rem-calc(12);
+ width: auto;
+
+ optgroup {
+ font-size: rem-calc(14);
+ }
+
+ option {
+
+ &:after {
+ content: "a";
+ font-family: "icons";
+ }
+ }
+ }
+}
+
+// 12. Officials levels
+// - - - - - - - - - - - - - - - - - - - - - - - - -
+
+.level-0 {
+ background: $level-0;
+}
+
+.level-1 {
+ background: $level-1;
+}
+
+.level-2 {
+ background: $level-2;
+}
+
+.level-3 {
+ background: $level-3;
+}
+
+.level-4 {
+ background: $level-4;
+}
+
+.level-5 {
+ background: $level-5;
+}
diff --git a/app/assets/stylesheets/variables.scss b/app/assets/stylesheets/variables.scss
index ca40c4e53..301598bbe 100644
--- a/app/assets/stylesheets/variables.scss
+++ b/app/assets/stylesheets/variables.scss
@@ -38,6 +38,13 @@ $votes-unlike-act: #BD6A6A;
$check: #46DB91;
+$level-0: #F08A24;
+$level-1: #43AC6A;
+$level-2: #43AC6A;
+$level-3: #43AC6A;
+$level-4: #43AC6A;
+$level-5: #43AC6A;
+
// 03. Forms
// - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/app/controllers/account_controller.rb b/app/controllers/account_controller.rb
index a5cf4e07e..091a280e6 100644
--- a/app/controllers/account_controller.rb
+++ b/app/controllers/account_controller.rb
@@ -11,6 +11,7 @@ class AccountController < ApplicationController
if @account.update(account_params)
redirect_to account_path, notice: t("flash.actions.save_changes.notice")
else
+ @account.errors.messages.delete(:organization)
render :show
end
end
@@ -22,7 +23,11 @@ class AccountController < ApplicationController
end
def account_params
- params.require(:account).permit(:first_name, :last_name, :nickname, :use_nickname, :email_on_debate_comment, :email_on_comment_reply)
+ if @account.organization?
+ params.require(:account).permit(:phone_number, :email_on_debate_comment, :email_on_comment_reply, organization_attributes: [:name])
+ else
+ params.require(:account).permit(:first_name, :last_name, :phone_number, :nickname, :use_nickname, :email_on_debate_comment, :email_on_comment_reply)
+ end
end
end
diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb
index f4322efe7..7a812104b 100644
--- a/app/controllers/admin/base_controller.rb
+++ b/app/controllers/admin/base_controller.rb
@@ -1,4 +1,5 @@
class Admin::BaseController < ApplicationController
+ layout 'admin'
before_action :authenticate_user!
skip_authorization_check
@@ -10,4 +11,4 @@ class Admin::BaseController < ApplicationController
raise CanCan::AccessDenied unless current_user.try(:administrator?)
end
-end
\ No newline at end of file
+end
diff --git a/app/controllers/admin/comments_controller.rb b/app/controllers/admin/comments_controller.rb
new file mode 100644
index 000000000..4c385b5d4
--- /dev/null
+++ b/app/controllers/admin/comments_controller.rb
@@ -0,0 +1,13 @@
+class Admin::CommentsController < Admin::BaseController
+
+ def index
+ @comments = Comment.only_hidden
+ end
+
+ def restore
+ @comment = Comment.with_hidden.find(params[:id])
+ @comment.restore
+ redirect_to admin_comments_path, notice: t('admin.comments.restore.success')
+ end
+
+end
\ No newline at end of file
diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb
index 870d7ef55..f7aa5c440 100644
--- a/app/controllers/admin/dashboard_controller.rb
+++ b/app/controllers/admin/dashboard_controller.rb
@@ -1,5 +1,4 @@
class Admin::DashboardController < Admin::BaseController
- layout 'admin'
def index
end
diff --git a/app/controllers/admin/debates_controller.rb b/app/controllers/admin/debates_controller.rb
new file mode 100644
index 000000000..a37744f71
--- /dev/null
+++ b/app/controllers/admin/debates_controller.rb
@@ -0,0 +1,16 @@
+class Admin::DebatesController < Admin::BaseController
+
+ def index
+ @debates = Debate.only_hidden
+ end
+
+ def show
+ @debate = Debate.with_hidden.find(params[:id])
+ end
+
+ def restore
+ @debate = Debate.with_hidden.find(params[:id])
+ @debate.restore
+ redirect_to admin_debates_path, notice: t('admin.debates.restore.success')
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/admin/officials_controller.rb b/app/controllers/admin/officials_controller.rb
new file mode 100644
index 000000000..023f0f7fc
--- /dev/null
+++ b/app/controllers/admin/officials_controller.rb
@@ -0,0 +1,32 @@
+class Admin::OfficialsController < Admin::BaseController
+
+ def index
+ @officials = User.officials.page(params[:page])
+ end
+
+ def search
+ @users = User.with_email(params[:email]).page(params[:page])
+ end
+
+ def edit
+ @user = User.find(params[:id])
+ end
+
+ def update
+ @user = User.find(params[:id])
+ @user.update(user_params)
+ redirect_to admin_officials_path, notice: t("admin.officials.flash.official_updated")
+ end
+
+ def destroy
+ @official = User.officials.find(params[:id])
+ @official.remove_official_position!
+ redirect_to admin_officials_path, notice: t("admin.officials.flash.official_destroyed")
+ end
+
+ private
+ def user_params
+ params.require(:user).permit(:official_position, :official_level)
+ end
+
+end
\ No newline at end of file
diff --git a/app/controllers/admin/organizations_controller.rb b/app/controllers/admin/organizations_controller.rb
new file mode 100644
index 000000000..c7e3c159c
--- /dev/null
+++ b/app/controllers/admin/organizations_controller.rb
@@ -0,0 +1,32 @@
+class Admin::OrganizationsController < Admin::BaseController
+ before_filter :set_valid_filters
+ before_filter :parse_filter
+
+ load_and_authorize_resource
+
+ def index
+ @organizations = @organizations.send(@filter)
+ @organizations = @organizations.includes(:user).order(:name, 'users.email')
+ end
+
+ def verify
+ @organization.verify
+ redirect_to action: :index, filter: @filter
+ end
+
+ def reject
+ @organization.reject
+ redirect_to action: :index, filter: @filter
+ end
+
+ private
+ def set_valid_filters
+ @valid_filters = %w{all pending verified rejected}
+ end
+
+ def parse_filter
+ @filter = params[:filter]
+ @filter = 'all' unless @valid_filters.include?(@filter)
+ end
+
+end
diff --git a/app/controllers/admin/settings_controller.rb b/app/controllers/admin/settings_controller.rb
new file mode 100644
index 000000000..b369d2cbc
--- /dev/null
+++ b/app/controllers/admin/settings_controller.rb
@@ -0,0 +1,17 @@
+class Admin::SettingsController < Admin::BaseController
+
+ def index
+ @settings = Setting.all
+ end
+
+ def update
+ @setting = Setting.find(params[:id])
+ @setting.update(settings_params)
+ redirect_to admin_settings_path, notice: t("admin.settings.flash.updated")
+ end
+
+ private
+ def settings_params
+ params.require(:setting).permit(:value)
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/admin/tags_controller.rb b/app/controllers/admin/tags_controller.rb
index ecacdbdb2..03cfeb64f 100644
--- a/app/controllers/admin/tags_controller.rb
+++ b/app/controllers/admin/tags_controller.rb
@@ -1,5 +1,4 @@
class Admin::TagsController < Admin::BaseController
- layout 'admin'
before_action :find_tag, only: [:update, :destroy]
respond_to :html, :js
diff --git a/app/controllers/api/api_controller.rb b/app/controllers/api/api_controller.rb
new file mode 100644
index 000000000..a7d0c1ea7
--- /dev/null
+++ b/app/controllers/api/api_controller.rb
@@ -0,0 +1,13 @@
+class Api::ApiController < ApplicationController
+ before_action :authenticate_user!
+ protect_from_forgery with: :null_session
+
+ skip_authorization_check
+ before_action :verify_administrator
+
+ private
+
+ def verify_administrator
+ raise CanCan::AccessDenied unless current_user.try(:administrator?)
+ end
+end
diff --git a/app/controllers/api/stats_controller.rb b/app/controllers/api/stats_controller.rb
new file mode 100644
index 000000000..d44262b45
--- /dev/null
+++ b/app/controllers/api/stats_controller.rb
@@ -0,0 +1,22 @@
+class Api::StatsController < Api::ApiController
+ def show
+ unless params[:events].present? || params[:visits].present?
+ return render json: {}, status: :bad_request
+ end
+
+ ds = Ahoy::DataSource.new
+
+ if params[:events].present?
+ event_types = params[:events].split ','
+ event_types.each do |event|
+ ds.add event.titleize, Ahoy::Event.where(name: event).group_by_day(:time).count
+ end
+ end
+
+ if params[:visits].present?
+ ds.add "Visits", Visit.group_by_day(:started_at).count
+ end
+
+ render json: ds.build
+ end
+end
diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb
index 71de112a9..a10d80da9 100644
--- a/app/controllers/comments_controller.rb
+++ b/app/controllers/comments_controller.rb
@@ -2,6 +2,7 @@ class CommentsController < ApplicationController
before_action :authenticate_user!
before_action :build_comment, only: :create
before_action :parent, only: :create
+
load_and_authorize_resource
respond_to :html, :js
@@ -50,4 +51,5 @@ class CommentsController < ApplicationController
def email_on_comment_reply?
reply? && parent.author.email_on_comment_reply?
end
+
end
diff --git a/app/controllers/debates_controller.rb b/app/controllers/debates_controller.rb
index 0816245c7..4f56b45ab 100644
--- a/app/controllers/debates_controller.rb
+++ b/app/controllers/debates_controller.rb
@@ -1,14 +1,17 @@
class DebatesController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
+
load_and_authorize_resource
+ respond_to :html, :js
def index
- @debates = Debate.search(params)
+ @debates = Debate.includes(:tags).search(params)
set_debate_votes(@debates)
end
def show
set_debate_votes(@debate)
+ @comments = @debate.root_comments.with_hidden.recent
end
def new
@@ -23,7 +26,9 @@ class DebatesController < ApplicationController
def create
@debate = Debate.new(debate_params)
@debate.author = current_user
+
if @debate.save_with_captcha
+ ahoy.track :debate_created, debate_id: @debate.id
redirect_to @debate, notice: t('flash.actions.create.notice', resource_name: 'Debate')
else
load_featured_tags
@@ -46,7 +51,6 @@ class DebatesController < ApplicationController
set_debate_votes(@debate)
end
-
private
def debate_params
diff --git a/app/controllers/moderation/base_controller.rb b/app/controllers/moderation/base_controller.rb
index 0ee155e03..f2a794526 100644
--- a/app/controllers/moderation/base_controller.rb
+++ b/app/controllers/moderation/base_controller.rb
@@ -1,4 +1,6 @@
class Moderation::BaseController < ApplicationController
+ layout 'admin'
+
before_action :authenticate_user!
skip_authorization_check
diff --git a/app/controllers/moderation/comments_controller.rb b/app/controllers/moderation/comments_controller.rb
new file mode 100644
index 000000000..c250fc460
--- /dev/null
+++ b/app/controllers/moderation/comments_controller.rb
@@ -0,0 +1,8 @@
+class Moderation::CommentsController < Moderation::BaseController
+
+ def hide
+ @comment = Comment.find(params[:id])
+ @comment.hide
+ end
+
+end
\ No newline at end of file
diff --git a/app/controllers/moderation/dashboard_controller.rb b/app/controllers/moderation/dashboard_controller.rb
index 86196af37..ceaddd6f4 100644
--- a/app/controllers/moderation/dashboard_controller.rb
+++ b/app/controllers/moderation/dashboard_controller.rb
@@ -1,5 +1,4 @@
class Moderation::DashboardController < Moderation::BaseController
- layout 'admin'
def index
end
diff --git a/app/controllers/moderation/debates_controller.rb b/app/controllers/moderation/debates_controller.rb
new file mode 100644
index 000000000..cb5599092
--- /dev/null
+++ b/app/controllers/moderation/debates_controller.rb
@@ -0,0 +1,7 @@
+class Moderation::DebatesController < Moderation::BaseController
+
+ def hide
+ @debate = Debate.find(params[:id])
+ @debate.hide
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/organizations/registrations_controller.rb b/app/controllers/organizations/registrations_controller.rb
new file mode 100644
index 000000000..8602ba4ba
--- /dev/null
+++ b/app/controllers/organizations/registrations_controller.rb
@@ -0,0 +1,26 @@
+class Organizations::RegistrationsController < Devise::RegistrationsController
+ def new
+ super do |user|
+ user.build_organization
+ end
+ end
+
+ def create
+ build_resource(sign_up_params)
+ if resource.valid_with_captcha?
+ super do |user|
+ # Removes unuseful "organization is invalid" error message
+ user.errors.messages.delete(:organization)
+ end
+ else
+ render :new
+ end
+ end
+
+ private
+
+ def sign_up_params
+ params.require(:user).permit(:email, :password, :phone_number, :password_confirmation, :captcha, :captcha_key, organization_attributes: [:name])
+ end
+
+end
diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb
new file mode 100644
index 000000000..1e76feb42
--- /dev/null
+++ b/app/controllers/stats_controller.rb
@@ -0,0 +1,14 @@
+class StatsController < ApplicationController
+ skip_authorization_check
+ before_action :verify_administrator
+
+ def show
+ @event_types = Ahoy::Event.select(:name).uniq.pluck(:name)
+ end
+
+ private
+
+ def verify_administrator
+ raise CanCan::AccessDenied unless current_user.try(:administrator?)
+ end
+end
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/users/registrations_controller.rb
similarity index 58%
rename from app/controllers/registrations_controller.rb
rename to app/controllers/users/registrations_controller.rb
index a3449ca8b..65da7e1e0 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/users/registrations_controller.rb
@@ -1,4 +1,4 @@
-class RegistrationsController < Devise::RegistrationsController
+class Users::RegistrationsController < Devise::RegistrationsController
def create
build_resource(sign_up_params)
@@ -9,11 +9,10 @@ class RegistrationsController < Devise::RegistrationsController
end
end
-
private
def sign_up_params
- params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :use_nickname, :nickname, :captcha, :captcha_key)
+ params.require(:user).permit(:first_name, :last_name, :email, :phone_number, :password, :password_confirmation, :use_nickname, :nickname, :captcha, :captcha_key)
end
end
diff --git a/app/controllers/welcome_controller.rb b/app/controllers/welcome_controller.rb
index 923609fab..b692ce32e 100644
--- a/app/controllers/welcome_controller.rb
+++ b/app/controllers/welcome_controller.rb
@@ -2,7 +2,7 @@ class WelcomeController < ApplicationController
skip_authorization_check
def index
- @featured_debates = Debate.limit(9)
+ @featured_debates = Debate.includes(:tags).limit(9)
set_debate_votes(@featured_debates)
end
diff --git a/app/helpers/abilities_helper.rb b/app/helpers/abilities_helper.rb
new file mode 100644
index 000000000..462af0479
--- /dev/null
+++ b/app/helpers/abilities_helper.rb
@@ -0,0 +1,7 @@
+module AbilitiesHelper
+
+ def moderator?
+ current_user.try(:moderator?)
+ end
+
+end
\ No newline at end of file
diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb
index a7fef3aa2..09d325e08 100644
--- a/app/helpers/admin_helper.rb
+++ b/app/helpers/admin_helper.rb
@@ -4,6 +4,14 @@ module AdminHelper
render "/#{namespace}/menu"
end
+ def official_level_options
+ options = []
+ (0..5).each do |i|
+ options << [[t("admin.officials.level_#{i}"), Setting.value_for("official_level_#{i}_name")].compact.join(': '), i]
+ end
+ options
+ end
+
private
def namespace
diff --git a/app/helpers/stats_helper.rb b/app/helpers/stats_helper.rb
new file mode 100644
index 000000000..e517767e3
--- /dev/null
+++ b/app/helpers/stats_helper.rb
@@ -0,0 +1,16 @@
+module StatsHelper
+ def events_chart_tag(events, opt={})
+ events = events.join(',') if events.is_a? Array
+ opt[:data] ||= {}
+ opt[:data][:graph] = api_stats_path(events: events)
+ content_tag :div, "", opt
+ end
+
+ def visits_chart_tag(opt={})
+ events = events.join(',') if events.is_a? Array
+ opt[:data] ||= {}
+ opt[:data][:graph] = api_stats_path(visits: true)
+ content_tag :div, "", opt
+ end
+
+end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index c1fc24ae3..9cce129a2 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -8,17 +8,31 @@ class Ability
if user # logged-in users
can [:read, :update], User, id: user.id
- can [:read, :create, :vote], Debate
+ can :read, Debate
can :update, Debate do |debate|
debate.editable_by?(user)
end
- can [:create, :vote], Comment
+ can :create, Comment
+ can :create, Debate
- if user.moderator? or user.administrator?
+ unless user.organization?
+ can :vote, Debate
+ can :vote, Comment
+ end
- elsif user.administrator?
+ if user.moderator? || user.administrator?
+ can :read, Organization
+ can(:verify, Organization){ |o| !o.verified? }
+ can(:reject, Organization){ |o| !o.rejected? }
+ can :hide, Comment
+ can :hide, Debate
+ end
+
+ if user.administrator?
+ can :restore, Comment
+ can :restore, Debate
end
end
end
diff --git a/app/models/ahoy/data_source.rb b/app/models/ahoy/data_source.rb
new file mode 100644
index 000000000..2d52063bb
--- /dev/null
+++ b/app/models/ahoy/data_source.rb
@@ -0,0 +1,49 @@
+# This class combines multiple collections with shared keys into a
+# hash of collections compatible with C3.js charts
+#----------------------------------------------------------------------
+
+module Ahoy
+ class DataSource
+
+ # Adds a collection with the datasource
+ # Name is the name of the collection and will be showed in the
+ # chart
+ def add(name, collection)
+ collections.push data: collection, name: name
+ collection.each{ |k,v| add_key k }
+ end
+
+ def build
+ data = { x: [] }
+ keys.each do |k|
+ # Add the key with a valid date format
+ data[:x].push k.strftime("%Y-%m-%d")
+
+ # Add the value for each column, or 0 if not present
+ collections.each do |col|
+ data[col[:name]] ||= []
+ count = col[:data][k] || 0
+ data[col[:name]].push count
+ end
+ end
+
+ return data
+ end
+
+ private
+
+ def collections
+ @collections ||= []
+ end
+
+ def keys
+ @keys ||= []
+ end
+
+ def add_key(key)
+ keys.push(key) unless keys.include? key
+ end
+
+ end
+
+end
diff --git a/app/models/ahoy/event.rb b/app/models/ahoy/event.rb
new file mode 100644
index 000000000..2aac3c59c
--- /dev/null
+++ b/app/models/ahoy/event.rb
@@ -0,0 +1,8 @@
+module Ahoy
+ class Event < ActiveRecord::Base
+ self.table_name = "ahoy_events"
+
+ belongs_to :visit
+ belongs_to :user
+ end
+end
diff --git a/app/models/comment.rb b/app/models/comment.rb
index b8182b04f..0141c1ffa 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -1,5 +1,8 @@
class Comment < ActiveRecord::Base
+ include ActsAsParanoidAliases
acts_as_nested_set scope: [:commentable_id, :commentable_type], counter_cache: :children_count
+
+ acts_as_paranoid column: :hidden_at
acts_as_votable
validates :body, presence: true
@@ -8,6 +11,7 @@ class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
belongs_to :user
+ default_scope { includes(:user) }
scope :recent, -> { order(id: :desc) }
def self.build(commentable, user, body)
diff --git a/app/models/debate.rb b/app/models/debate.rb
index b0d022c51..7d39384d5 100644
--- a/app/models/debate.rb
+++ b/app/models/debate.rb
@@ -1,5 +1,6 @@
require 'numeric'
class Debate < ActiveRecord::Base
+ include ActsAsParanoidAliases
default_scope { order('created_at DESC') }
apply_simple_captcha
@@ -8,6 +9,7 @@ class Debate < ActiveRecord::Base
acts_as_votable
acts_as_commentable
acts_as_taggable
+ acts_as_paranoid column: :hidden_at
belongs_to :author, class_name: 'User', foreign_key: 'author_id'
@@ -20,6 +22,9 @@ class Debate < ActiveRecord::Base
before_validation :sanitize_description
before_validation :sanitize_tag_list
+ # Ahoy setup
+ visitable # Ahoy will automatically assign visit_id on create
+
def self.search(params)
if params[:tag]
tagged_with(params[:tag])
diff --git a/app/models/organization.rb b/app/models/organization.rb
new file mode 100644
index 000000000..de120de9e
--- /dev/null
+++ b/app/models/organization.rb
@@ -0,0 +1,31 @@
+class Organization < ActiveRecord::Base
+
+ belongs_to :user
+
+ validates :name, presence: true
+
+ delegate :email, :phone_number, to: :user
+
+ scope :pending, -> { where(verified_at: nil, rejected_at: nil) }
+ scope :verified, -> { where("verified_at is not null and (rejected_at is null or rejected_at < verified_at)") }
+ scope :rejected, -> { where("rejected_at is not null and (verified_at is null or verified_at < rejected_at)") }
+
+ def verify
+ update(verified_at: Time.now)
+ end
+
+ def reject
+ update(rejected_at: Time.now)
+ end
+
+ def verified?
+ verified_at.present? &&
+ (rejected_at.blank? || rejected_at < verified_at)
+ end
+
+ def rejected?
+ rejected_at.present? &&
+ (verified_at.blank? || verified_at < rejected_at)
+ end
+
+end
diff --git a/app/models/setting.rb b/app/models/setting.rb
new file mode 100644
index 000000000..1a52ebe60
--- /dev/null
+++ b/app/models/setting.rb
@@ -0,0 +1,7 @@
+class Setting < ActiveRecord::Base
+ default_scope { order(key: :desc) }
+
+ def self.value_for(key)
+ where(key: key).pluck(:value).first
+ end
+end
\ No newline at end of file
diff --git a/app/models/user.rb b/app/models/user.rb
index 205a6bf5f..0bb85937f 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -5,12 +5,29 @@ class User < ActiveRecord::Base
acts_as_voter
- validates :first_name, presence: true, unless: :use_nickname?
- validates :last_name, presence: true, unless: :use_nickname?
- validates :nickname, presence: true, if: :use_nickname?
+ has_one :administrator
+ has_one :moderator
+ has_one :organization
+
+ validates :first_name, presence: true, if: :use_first_name?
+ validates :last_name, presence: true, if: :use_last_name?
+ validates :nickname, presence: true, if: :use_nickname?
+ validates :official_level, inclusion: {in: 0..5}
+
+ 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") }
def name
- use_nickname? ? nickname : "#{first_name} #{last_name}"
+ return nickname if use_nickname?
+ return organization.name if organization?
+ "#{first_name} #{last_name}"
end
def debate_votes(debates)
@@ -19,10 +36,40 @@ class User < ActiveRecord::Base
end
def administrator?
- @is_administrator ||= Administrator.where(user_id: id).exists?
+ administrator.present?
end
def moderator?
- @is_moderator ||= Moderator.where(user_id: id).exists?
+ moderator.present?
end
+
+ def organization?
+ organization.present?
+ end
+
+ def official?
+ official_level && official_level > 0
+ end
+
+ def add_official_position!(position, level)
+ return if position.blank? || level.blank?
+ update official_position: position, official_level: level.to_i
+ end
+
+ def remove_official_position!
+ update official_position: nil, official_level: 0
+ end
+
+ def self.with_email(e)
+ e.present? ? where(email: e) : none
+ end
+
+ private
+ def use_first_name?
+ !organization? && !use_nickname?
+ end
+
+ def use_last_name?
+ use_first_name?
+ end
end
diff --git a/app/models/visit.rb b/app/models/visit.rb
new file mode 100644
index 000000000..6bb47fed0
--- /dev/null
+++ b/app/models/visit.rb
@@ -0,0 +1,4 @@
+class Visit < ActiveRecord::Base
+ has_many :ahoy_events, class_name: "Ahoy::Event"
+ belongs_to :user
+end
diff --git a/app/views/account/show.html.erb b/app/views/account/show.html.erb
index d38f63df7..fb647ef1d 100644
--- a/app/views/account/show.html.erb
+++ b/app/views/account/show.html.erb
@@ -11,12 +11,24 @@
<%= t("account.show.personal")%>
- <%= f.text_field :first_name, placeholder: t("account.show.first_name_label") %>
- <%= f.text_field :last_name, placeholder: t("account.show.last_name_label") %>
- <%= f.text_field :nickname, placeholder: t("account.show.nickname_label") %>
+ <% if @account.organization? %>
- <%= f.check_box :use_nickname, label: false %>
- <%= t("account.show.use_nickname_label") %>
+ <%= f.fields_for :organization do |fo| %>
+ <%= fo.text_field :name, autofocus: true, placeholder: t("account.show.organization_name_label") %>
+ <% end %>
+
+ <% else %>
+
+ <%= f.text_field :first_name, placeholder: t("account.show.first_name_label") %>
+ <%= f.text_field :last_name, placeholder: t("account.show.last_name_label") %>
+ <%= f.text_field :nickname, placeholder: t("account.show.nickname_label") %>
+
+ <%= f.check_box :use_nickname, label: false %>
+ <%= t("account.show.use_nickname_label") %>
+
+ <% end %>
+
+ <%= f.text_field :phone_number, placeholder: t("account.show.phone_number_label") %>
@@ -41,5 +53,6 @@
<% end %>
+
-
\ No newline at end of file
+
diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb
index 79540a5d0..06cdac5ca 100644
--- a/app/views/admin/_menu.html.erb
+++ b/app/views/admin/_menu.html.erb
@@ -1,3 +1,56 @@
-
+
diff --git a/app/views/admin/comments/index.html.erb b/app/views/admin/comments/index.html.erb
new file mode 100644
index 000000000..c8c7faa8e
--- /dev/null
+++ b/app/views/admin/comments/index.html.erb
@@ -0,0 +1,18 @@
+<%= t("admin.comments.index.title") %>
+
+
+ <% @comments.each do |comment| %>
+
+ <% end %>
+
diff --git a/app/views/admin/dashboard/index.html.erb b/app/views/admin/dashboard/index.html.erb
index ffc8a281a..8cea6ce36 100644
--- a/app/views/admin/dashboard/index.html.erb
+++ b/app/views/admin/dashboard/index.html.erb
@@ -1 +1,5 @@
-<%= t("admin.dashboard.index.title") %>
+<%= t("admin.dashboard.index.title") %>
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+
+Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.
diff --git a/app/views/admin/debates/index.html.erb b/app/views/admin/debates/index.html.erb
new file mode 100644
index 000000000..e7e1e5753
--- /dev/null
+++ b/app/views/admin/debates/index.html.erb
@@ -0,0 +1,13 @@
+<%= t("admin.debates.index.title") %>
+
+
+ <% @debates.each do |debate| %>
+ -
+ <%= link_to debate.title, admin_debate_path(debate) %>
+
+ <%= link_to t("admin.actions.restore"), restore_admin_debate_path(debate),
+ method: :put, data: { confirm: t("admin.actions.confirm") },
+ class: "button radius tiny success right" %>
+
+ <% end %>
+
diff --git a/app/views/admin/debates/show.html.erb b/app/views/admin/debates/show.html.erb
new file mode 100644
index 000000000..e740baf47
--- /dev/null
+++ b/app/views/admin/debates/show.html.erb
@@ -0,0 +1,12 @@
+<%= t("admin.debates.index.title") %>
+
+<%= @debate.title %>
+
+<%= @debate.description %>
+
+<%= link_to t("admin.debates.show.back"), admin_debates_path,
+ class: "button radius small secondary" %>
+
+<%= link_to t("admin.actions.restore"), restore_admin_debate_path(@debate),
+ method: :put, data: { confirm: t("admin.actions.confirm") },
+ class: "button radius small success" %>
diff --git a/app/views/admin/officials/edit.html.erb b/app/views/admin/officials/edit.html.erb
new file mode 100644
index 000000000..f5748d77f
--- /dev/null
+++ b/app/views/admin/officials/edit.html.erb
@@ -0,0 +1,15 @@
+
+ <%= t("admin.officials.edit.title") %>
+ <%= @user.name %> (<%= @user.email %>)
+
+
+<%= form_for @user, url: admin_official_path(@user) do |f| %>
+ <%= f.text_field :official_position %>
+ <%= f.select :official_level, official_level_options %>
+ <%= link_to t("admin.officials.edit.back"), admin_officials_path, class: "button radius small secondary" %>
+ <%= f.submit %>
+
+ <% if @user.official? %>
+ <%= link_to t("admin.officials.edit.destroy"), admin_official_path(@user), method: :delete, class: 'delete' %>
+ <% end %>
+<% end %>
diff --git a/app/views/admin/officials/index.html.erb b/app/views/admin/officials/index.html.erb
new file mode 100644
index 000000000..bb2f006ab
--- /dev/null
+++ b/app/views/admin/officials/index.html.erb
@@ -0,0 +1,32 @@
+<%= t("admin.officials.index.title") %>
+
+<%= form_for(User.new, url: search_admin_officials_path, as: :user, method: :get) do |f| %>
+
+
+ <%= text_field_tag :email, "", placeholder: t("admin.officials.index.search_email_placeholder") %>
+
+
+ <%= f.submit t("admin.officials.index.search"), class: "button radius success" %>
+
+
+<% end %>
+
+<%= page_entries_info @officials %>
+
+
+<% @officials.each do |official| %>
+ -
+ <%= link_to official.name, edit_admin_official_path(official) %>
+ •
+ <%= t("admin.officials.level_#{official.official_level}") %>
+ •
+
+ <%= official.official_position %>
+
+
+ <%= link_to official.official? ? t("admin.officials.search.edit_official") : t("admin.officials.search.make_official"), edit_admin_official_path(official), class: "button radius tiny right" %>
+
+<% end %>
+
+
+<%= paginate @officials %>
diff --git a/app/views/admin/officials/search.html.erb b/app/views/admin/officials/search.html.erb
new file mode 100644
index 000000000..a7f60ca8a
--- /dev/null
+++ b/app/views/admin/officials/search.html.erb
@@ -0,0 +1,30 @@
+<%= t("admin.officials.search.title") %>
+
+<%= form_for(User.new, url: search_admin_officials_path, as: :user, method: :get) do |f| %>
+
+
+ <%= text_field_tag :email, "", placeholder: t("admin.officials.index.search_email_placeholder") %>
+
+
+ <%= f.submit t("admin.officials.search.search"), class: "button radius success" %>
+
+
+<% end %>
+
+<%= page_entries_info @users %>
+
+
+ <% @users.each do |user| %>
+ -
+ <%= link_to user.name, edit_admin_official_path(user) %>
+ •
+
+ <%= user.official_position %>
+
+ •
+ <%= t("admin.officials.level_#{user.official_level}") %>
+
+ <%= link_to user.official? ? t("admin.officials.search.edit_official") : t("admin.officials.search.make_official"), edit_admin_official_path(user), class: "button radius tiny right" %>
+
+ <% end %>
+
diff --git a/app/views/admin/organizations/index.html.erb b/app/views/admin/organizations/index.html.erb
new file mode 100644
index 000000000..b22dfdbc9
--- /dev/null
+++ b/app/views/admin/organizations/index.html.erb
@@ -0,0 +1,48 @@
+
+
+
<%= t('admin.organizations.index.title') %>
+
+
+ <%= t('admin.organizations.index.filter') %>:
+
+ <% @valid_filters.each do |filter| %>
+ <% if @filter == filter %>
+ <%= t("admin.organizations.index.filters.#{filter}") %>
+ <% else %>
+ <%= link_to t("admin.organizations.index.filters.#{filter}"),
+ admin_organizations_path(filter: filter) %>
+ <% end %>
+ <% end %>
+
+
+
+ <% @organizations.each do |organization| %>
+
+ | <%= organization.name %> |
+ <%= organization.email %> |
+ <%= organization.phone_number %> |
+ <% if organization.verified? %>
+ <%= t('admin.organizations.index.verified') %> |
+ <% end %>
+ <% if can? :verify, organization %>
+ <%= link_to t('admin.organizations.index.verify'),
+ verify_admin_organization_path(organization, filter: @filter),
+ method: :put
+ %>
+ |
+ <% end %>
+ <% if organization.rejected? %>
+ <%= t('admin.organizations.index.rejected') %> |
+ <% end %>
+ <% if can? :reject, organization %>
+ <%= link_to t('admin.organizations.index.reject'),
+ reject_admin_organization_path(organization, filter: @filter),
+ method: :put
+ %>
+ |
+ <% end %>
+
+ <% end %>
+
+
+
diff --git a/app/views/admin/settings/index.html.erb b/app/views/admin/settings/index.html.erb
new file mode 100644
index 000000000..c18c13b8a
--- /dev/null
+++ b/app/views/admin/settings/index.html.erb
@@ -0,0 +1,14 @@
+<%= t("admin.settings.index.title") %>
+
+
+ <% @settings.each do |setting| %>
+ -
+ <%= setting.key.classify %>
+
+ <%= form_for(setting, url: admin_setting_path(setting), html: { id: "edit_#{dom_id(setting)}"}) do |f| %>
+ <%= f.text_field :value, label: false, id: dom_id(setting) %>
+ <%= f.submit(class: "button radius tiny success") %>
+ <% end %>
+
+ <% end %>
+
diff --git a/app/views/admin/tags/index.html.erb b/app/views/admin/tags/index.html.erb
index 4dbbed167..f6f14d5da 100644
--- a/app/views/admin/tags/index.html.erb
+++ b/app/views/admin/tags/index.html.erb
@@ -1,29 +1,46 @@
-
-
<%= t("admin.tags.index.add_tag") %>
+
<%= t("admin.tags.index.add_tag") %>
- <%= form_for(@tag, url: admin_tags_path, as: :tag) do |f| %>
- <%= f.text_field :name, placeholder: t("admin.tags.name.placeholder") %>
- <%= f.check_box :featured, label: false %>
- <%= t("admin.tags.mark_as_featured") %>
- <%= f.submit(class: "button radius small") %>
- <% end %>
+<%= form_for(@tag, url: admin_tags_path, as: :tag) do |f| %>
+
+
+ <%= f.label :name, t("admin.tags.name.placeholder") %>
+ <%= f.text_field :name, placeholder: t("admin.tags.name.placeholder"), label: false %>
+
-
<%= t("admin.tags.index.title") %>
+
+ <%= f.label :featured do %>
+ <%= f.check_box :featured, label: false %>
+ <%= t("admin.tags.mark_as_featured") %>
+ <% end %>
+
+
-
- <% @tags.each do |tag| %>
- -
- <%= tag.name %>
+ <%= f.submit(class: "button radius success") %>
- <%= form_for(tag, url: admin_tag_path(tag), as: :tag, html: { id: "edit_tag_#{tag.id}"}) do |f| %>
- <%= f.check_box :featured, label: false, id: "tag_featured_#{tag.id}" %>
- <%= t("admin.tags.mark_as_featured") %>
- <%= f.submit(class: "button radius tiny") %>
- <%= link_to t("admin.tags.destroy"), admin_tag_path(tag), method: :delete, class: 'button tiny alert' %>
+<% end %>
+
+
<%= t("admin.tags.index.title") %>
+
+
+ <% @tags.each do |tag| %>
+ -
+ <%= tag.name %>
+
+ <%= form_for(tag,
+ url: admin_tag_path(tag),
+ as: :tag,
+ html: { id: "edit_tag_#{tag.id}", class: "text-right"}) do |f| %>
+
+ <%= f.label "featured_#{tag.id}" do %>
+ <%= f.check_box :featured, label: false, id: "tag_featured_#{tag.id}", class: "left" %>
+ <%= t("admin.tags.mark_as_featured") %>
<% end %>
-
- <% end %>
-
-
+ <%= f.submit(class: "button radius tiny success") %>
+
+ <%= link_to t("admin.tags.destroy"), admin_tag_path(tag), method: :delete, class: "delete" %>
+ <% end %>
+
+ <% end %>
+
diff --git a/app/views/comments/_actions.html.erb b/app/views/comments/_actions.html.erb
new file mode 100644
index 000000000..ecc9bc9c0
--- /dev/null
+++ b/app/views/comments/_actions.html.erb
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/app/views/comments/_comment.html.erb b/app/views/comments/_comment.html.erb
index af5a41897..b81b64915 100644
--- a/app/views/comments/_comment.html.erb
+++ b/app/views/comments/_comment.html.erb
@@ -1,30 +1,44 @@
\ No newline at end of file
diff --git a/app/views/comments/_form.html.erb b/app/views/comments/_form.html.erb
index da2b3bb61..d7fcb5cdd 100644
--- a/app/views/comments/_form.html.erb
+++ b/app/views/comments/_form.html.erb
@@ -1,5 +1,3 @@
-<%= link_to(comment_link_text(parent), "", class: "js-add-comment-link", data: {'id': dom_id(parent)}) if toggeable %>
-
diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb
deleted file mode 100644
index 980df3333..000000000
--- a/app/views/devise/registrations/edit.html.erb
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
<%= link_to t("devise_views.registrations.edit.back_link"), :back, class: "left back" %>
-
-
<%= t("devise_views.registrations.edit.edit") %> <%= resource_name.to_s.humanize %>
-
- <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
- <%= render 'shared/errors', resource: resource %>
-
-
-
- <%= f.email_field :email, autofocus: true, placeholder: t("devise_views.registrations.edit.email_label") %>
-
-
-
- <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
-
<%= t("devise_views.registrations.edit.waiting_for") %> <%= resource.unconfirmed_email %>
- <% end %>
-
-
-
- <%= f.label :password, t("devise_views.registrations.edit.password_label") %>
- <%= t("devise_views.registrations.edit.leave_blank") %>
- <%= f.password_field :password, autocomplete: "off",
- label: false,
- placeholder: t("devise_views.registrations.edit.password_label") %>
-
-
-
- <%= f.password_field :password_confirmation, autocomplete: "off", placeholder: t("devise_views.registrations.edit.password_confirmation_label") %>
-
-
-
- <%= f.label :current_password, t("devise_views.registrations.edit.current_password_label") %>
- <%= t("devise_views.registrations.edit.need_current") %>
- <%= f.password_field :current_password, autocomplete: "off",
- label: false,
- placeholder: t("devise_views.registrations.edit.current_password_label") %>
-
-
-
- <%= f.submit t("devise_views.registrations.edit.update_submit"), class: "button radius" %>
-
-
- <% end %>
-
-
-
\ No newline at end of file
diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb
index d7a77614e..0fd80f429 100644
--- a/app/views/devise/shared/_links.html.erb
+++ b/app/views/devise/shared/_links.html.erb
@@ -3,10 +3,16 @@
<%= link_to t("devise_views.shared.links.login"), new_session_path(resource_name) %>
<% end -%>
- <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
- <%= link_to t("devise_views.shared.links.signup"), new_registration_path(resource_name) %>
+ <%- if devise_mapping.registerable? &&
+ controller_name != 'registrations' ||
+ controller_path != 'users/registrations' %>
+ <%= link_to t("devise_views.shared.links.signup"), new_user_registration_path %>
<% end -%>
+ <%- if devise_mapping.registerable? && controller_name == 'registrations' && controller_path != 'organizations/registrations' %>
+ <%= link_to t("devise_views.shared.links.organization_signup"), new_organization_registration_path %>
+ <% end -%>
+
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
<%= link_to t("devise_views.shared.links.new_password"), new_password_path(resource_name) %>
<% end -%>
@@ -24,4 +30,5 @@
<%= link_to t("devise_views.shared.links.signin_with_provider", provider: provider.to_s.titleize), omniauth_authorize_path(resource_name, provider) %>
<% end -%>
<% end -%>
-
\ No newline at end of file
+
+
diff --git a/app/views/layouts/_admin_header.html.erb b/app/views/layouts/_admin_header.html.erb
new file mode 100644
index 000000000..ffd7d34f4
--- /dev/null
+++ b/app/views/layouts/_admin_header.html.erb
@@ -0,0 +1,44 @@
+
diff --git a/app/views/layouts/_header.html.erb b/app/views/layouts/_header.html.erb
index b88dcded4..d525c5c62 100644
--- a/app/views/layouts/_header.html.erb
+++ b/app/views/layouts/_header.html.erb
@@ -35,6 +35,21 @@
<%= render 'devise/menu/login_items' %>
<%= render 'shared/admin_login_items' %>
+
+
+
+ <%= link_to t("layouts.header.welcome"), root_path, class: ("active" if current_page?(root_path)) %>
+
+
+ <%= link_to t("layouts.header.news"), "#" %>
+
+
+ <%= link_to t("layouts.header.debates"), debates_path, class: ("active" if current_page?(controller: 'debates')) %>
+
+
+ <%= link_to t("layouts.header.initiatives"), "#" %>
+
+
diff --git a/app/views/layouts/admin.html.erb b/app/views/layouts/admin.html.erb
index b23b3e193..79ae8fcd9 100644
--- a/app/views/layouts/admin.html.erb
+++ b/app/views/layouts/admin.html.erb
@@ -12,22 +12,26 @@
<%= csrf_meta_tags %>
-
- <%= render 'layouts/header' %>
+
+ <%= render 'layouts/admin_header' %>
- <% if notice %>
- <%= notice %>
- <% end %>
+
- <% if alert %>
-
<%= alert %>
- <% end %>
+
+ <%= side_menu %>
+
-
- <%= side_menu %>
+
+ <% if notice %>
+
<%= notice %>
+ <% end %>
+
+ <% if alert %>
+
<%= alert %>
+ <% end %>
+
+ <%= yield %>
+
-
- <%= yield %>
-
-
\ No newline at end of file
+
<%= comment.body %>
+ <%= avatar_image(comment.user, size: 32, class: 'left') %> - - <%= render 'comments/votes', comment: comment %> - +<%= comment.body %>
-- <%= t("debates.comment.responses", count: comment.children_count) %> - <% if user_signed_in? %> - | - <%= render 'comments/form', {parent: comment, toggeable: true} %> - <% end %> -
-+ <%= t("debates.comment.responses", count: comment.children_count) %> + + <% if user_signed_in? %> + | + <%= link_to(comment_link_text(comment), "", + class: "js-add-comment-link", data: {'id': dom_id(comment)}) %> + + <% if moderator? %> + <%= render 'comments/actions', comment: comment %> + <% end %> + + <%= render 'comments/form', {parent: comment, toggeable: true} %> + <% end %> +
+