merge debats-ruby with debats-front

This commit is contained in:
Jalil Arfaoui 2024-01-05 01:18:44 +01:00
commit 32e09b9be9
270 changed files with 6661 additions and 0 deletions

8
ruby-backend/.generators Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<Settings><!--This file was automatically generated by Ruby plugin.
You are allowed to:
1. Reorder generators
2. Remove generators
3. Add installed generators
To add new installed generators automatically delete this file and reload the project.
--><GeneratorsGroup><Generator name="active_record:migration" /><Generator name="active_record:model" /><Generator name="active_record:observer" /><Generator name="active_record:session_migration" /><Generator name="controller" /><Generator name="erb:controller" /><Generator name="erb:mailer" /><Generator name="erb:scaffold" /><Generator name="generator" /><Generator name="helper" /><Generator name="integration_test" /><Generator name="mailer" /><Generator name="metal" /><Generator name="migration" /><Generator name="model" /><Generator name="model_subclass" /><Generator name="observer" /><Generator name="performance_test" /><Generator name="plugin" /><Generator name="resource" /><Generator name="scaffold" /><Generator name="scaffold_controller" /><Generator name="session_migration" /><Generator name="stylesheets" /><Generator name="test_unit:controller" /><Generator name="test_unit:helper" /><Generator name="test_unit:integration" /><Generator name="test_unit:mailer" /><Generator name="test_unit:model" /><Generator name="test_unit:observer" /><Generator name="test_unit:performance" /><Generator name="test_unit:plugin" /><Generator name="test_unit:scaffold" /></GeneratorsGroup></Settings>

23
ruby-backend/.gitignore vendored Normal file
View file

@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile '~/.gitignore_global'
# Ignore bundler config.
/.bundle
# Ignore the default SQLite database.
/db/*.sqlite3
/db/*.sqlite3-journal
# Ignore all logfiles and tempfiles.
/log/*
!/log/.keep
/tmp
.idea/
/public/uploads
db/schema.rb
db/seeds.rb

7
ruby-backend/.rakeTasks Normal file
View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Settings><!--This file was automatically generated by Ruby plugin.
You are allowed to:
1. Remove rake task
2. Add existing rake tasks
To add existing rake tasks automatically delete this file and reload the project.
--><RakeGroup description="" fullCmd="" taksId="rake" /></Settings>

87
ruby-backend/Gemfile Normal file
View file

@ -0,0 +1,87 @@
source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.3'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.1.0'
gem 'coffee-script-source', '1.8.0' # Problem with Coffee-script-source 1.9.0 on Windows
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby
# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'
gem 'jquery-turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.0'
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', '~> 0.4.0', group: :doc
# Custom responders (https://github.com/plataformatec/responders)
gem "responders"
# Paginate
gem "will_paginate"
gem "bootstrap-will_paginate"
# uploads and images
gem 'carrierwave', '0.10.0'
gem 'mini_magick', '3.8.0'
gem 'fog', '1.23.0'
# Use ActiveModel has_secure_password
gem 'bcrypt', '~> 3.1.7'
# friendly ids (slugs)
gem 'friendly_id'
# SSL
gem 'net-ssh'
######## UI #######
gem 'jquery-ui-rails' # JQuery UI
gem 'rails-jquery-autocomplete' # Rails JQuery Autocomplete
gem 'sass-rails', '~> 5.0' # Use SCSS for stylesheets
gem 'bootstrap-sass' # Boostrap with SASS
gem 'bootstrap-datepicker-rails' # Date picker
gem 'fuelux-rails-sass' # Fuel UX components
gem 'best_in_place' # in-place editing
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug'
# Access an IRB console on exception pages or by using <%= console %> in views
gem 'web-console', '~> 2.0'
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
end
group :development do
gem 'faker'
gem 'ruby-debug-ide'
gem 'debase'
end
group :test do
gem 'minitest-reporters'
gem 'mini_backtrace'
gem 'listen', '~> 2.10.1'
gem 'guard'
gem 'guard-minitest'
end
group :production, :staging do
gem 'pg'
gem 'rails_12factor'
gem 'puma'
end
ruby '2.1.8'

337
ruby-backend/Gemfile.lock Normal file
View file

@ -0,0 +1,337 @@
GEM
remote: https://rubygems.org/
specs:
actionmailer (4.2.3)
actionpack (= 4.2.3)
actionview (= 4.2.3)
activejob (= 4.2.3)
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)
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)
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)
globalid (>= 0.3.0)
activemodel (4.2.3)
activesupport (= 4.2.3)
builder (~> 3.1)
activerecord (4.2.3)
activemodel (= 4.2.3)
activesupport (= 4.2.3)
arel (~> 6.0)
activesupport (4.2.3)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
ansi (1.5.0)
arel (6.0.3)
autoprefixer-rails (6.3.7)
execjs
bcrypt (3.1.11)
bcrypt (3.1.11-x64-mingw32)
bcrypt (3.1.11-x86-mingw32)
best_in_place (3.1.0)
actionpack (>= 3.2)
railties (>= 3.2)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
bootstrap-datepicker-rails (1.6.1.1)
railties (>= 3.0)
bootstrap-sass (3.3.6)
autoprefixer-rails (>= 5.2.1)
sass (>= 3.3.4)
bootstrap-will_paginate (0.0.10)
will_paginate
builder (3.2.2)
byebug (9.0.5)
carrierwave (0.10.0)
activemodel (>= 3.2.0)
activesupport (>= 3.2.0)
json (>= 1.7)
mime-types (>= 1.16)
celluloid (0.16.0)
timers (~> 4.0.0)
coderay (1.1.1)
coffee-rails (4.1.1)
coffee-script (>= 2.2.0)
railties (>= 4.0.0, < 5.1.x)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.8.0)
concurrent-ruby (1.0.2)
debase (0.2.1)
debase-ruby_core_source
debase-ruby_core_source (0.9.1)
debug_inspector (0.0.2)
erubis (2.7.0)
excon (0.51.0)
execjs (2.7.0)
faker (1.6.5)
i18n (~> 0.5)
ffi (1.9.14)
ffi (1.9.14-x64-mingw32)
ffi (1.9.14-x86-mingw32)
fog (1.23.0)
fog-brightbox
fog-core (~> 1.23)
fog-json
fog-softlayer
ipaddress (~> 0.5)
nokogiri (~> 1.5, >= 1.5.11)
fog-brightbox (0.11.0)
fog-core (~> 1.22)
fog-json
inflecto (~> 0.0.2)
fog-core (1.42.0)
builder
excon (~> 0.49)
formatador (~> 0.2)
fog-json (1.0.2)
fog-core (~> 1.0)
multi_json (~> 1.10)
fog-softlayer (1.1.3)
fog-core
fog-json
formatador (0.2.5)
friendly_id (5.1.0)
activerecord (>= 4.0.0)
fuelux-rails-sass (3.14.2)
railties (>= 3.1)
sass-rails
globalid (0.3.6)
activesupport (>= 4.1.0)
guard (2.14.0)
formatador (>= 0.2.4)
listen (>= 2.7, < 4.0)
lumberjack (~> 1.0)
nenv (~> 0.1)
notiffany (~> 0.0)
pry (>= 0.9.12)
shellany (~> 0.0)
thor (>= 0.18.1)
guard-compat (1.2.1)
guard-minitest (2.4.5)
guard-compat (~> 1.2)
minitest (>= 3.0)
hitimes (1.2.4)
hitimes (1.2.4-x86-mingw32)
i18n (0.7.0)
inflecto (0.0.2)
ipaddress (0.8.3)
jbuilder (2.6.0)
activesupport (>= 3.0.0, < 5.1)
multi_json (~> 1.2)
jquery-rails (4.1.1)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
jquery-turbolinks (2.1.0)
railties (>= 3.1.0)
turbolinks
jquery-ui-rails (5.0.5)
railties (>= 3.2.16)
json (1.8.3)
listen (2.10.1)
celluloid (~> 0.16.0)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
loofah (2.0.3)
nokogiri (>= 1.5.9)
lumberjack (1.0.10)
mail (2.6.4)
mime-types (>= 1.16, < 4)
method_source (0.8.2)
mime-types (3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mini_backtrace (0.1.3)
minitest (> 1.2.0)
rails (>= 2.3.3)
mini_magick (3.8.0)
subexec (~> 0.2.1)
mini_portile2 (2.1.0)
minitest (5.9.0)
minitest-reporters (1.1.10)
ansi
builder
minitest (>= 5.0)
ruby-progressbar
multi_json (1.12.1)
nenv (0.3.0)
net-ssh (3.2.0)
nokogiri (1.6.8)
mini_portile2 (~> 2.1.0)
pkg-config (~> 1.1.7)
nokogiri (1.6.8-x64-mingw32)
mini_portile2 (~> 2.1.0)
pkg-config (~> 1.1.7)
nokogiri (1.6.8-x86-mingw32)
mini_portile2 (~> 2.1.0)
pkg-config (~> 1.1.7)
notiffany (0.1.0)
nenv (~> 0.1)
shellany (~> 0.0)
pg (0.18.4)
pg (0.18.4-x64-mingw32)
pg (0.18.4-x86-mingw32)
pkg-config (1.1.7)
pry (0.10.4)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
puma (3.5.2)
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)
bundler (>= 1.3.0, < 2.0)
railties (= 4.2.3)
sprockets-rails
rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha)
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.3)
loofah (~> 2.0)
rails-jquery-autocomplete (1.0.3)
rails (>= 3.2)
rails_12factor (0.0.3)
rails_serve_static_assets
rails_stdout_logging
rails_serve_static_assets (0.0.5)
rails_stdout_logging (0.0.5)
railties (4.2.3)
actionpack (= 4.2.3)
activesupport (= 4.2.3)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (11.2.2)
rb-fsevent (0.9.7)
rb-inotify (0.9.7)
ffi (>= 0.5.0)
rdoc (4.2.2)
json (~> 1.4)
responders (2.2.0)
railties (>= 4.2.0, < 5.1)
ruby-debug-ide (0.6.0)
rake (>= 0.8.1)
ruby-progressbar (1.8.1)
sass (3.4.22)
sass-rails (5.0.6)
railties (>= 4.0.0, < 6)
sass (~> 3.1)
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
sdoc (0.4.1)
json (~> 1.7, >= 1.7.7)
rdoc (~> 4.0)
shellany (0.0.1)
slop (3.6.0)
sprockets (3.7.0)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.1.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sqlite3 (1.3.11)
sqlite3 (1.3.11-x64-mingw32)
sqlite3 (1.3.11-x86-mingw32)
subexec (0.2.3)
thor (0.19.1)
thread_safe (0.3.5)
tilt (2.0.5)
timers (4.0.4)
hitimes
turbolinks (5.0.0)
turbolinks-source (~> 5)
turbolinks-source (5.0.0)
tzinfo (1.2.2)
thread_safe (~> 0.1)
tzinfo-data (1.2016.6)
tzinfo (>= 1.0.0)
uglifier (3.0.0)
execjs (>= 0.3.0, < 3)
web-console (2.3.0)
activemodel (>= 4.0)
binding_of_caller (>= 0.7.2)
railties (>= 4.0)
sprockets-rails (>= 2.0, < 4.0)
will_paginate (3.1.0)
PLATFORMS
ruby
x64-mingw32
x86-mingw32
DEPENDENCIES
bcrypt (~> 3.1.7)
best_in_place
bootstrap-datepicker-rails
bootstrap-sass
bootstrap-will_paginate
byebug
carrierwave (= 0.10.0)
coffee-rails (~> 4.1.0)
coffee-script-source (= 1.8.0)
debase
faker
fog (= 1.23.0)
friendly_id
fuelux-rails-sass
guard
guard-minitest
jbuilder (~> 2.0)
jquery-rails
jquery-turbolinks
jquery-ui-rails
listen (~> 2.10.1)
mini_backtrace
mini_magick (= 3.8.0)
minitest-reporters
net-ssh
pg
puma
rails (= 4.2.3)
rails-jquery-autocomplete
rails_12factor
responders
ruby-debug-ide
sass-rails (~> 5.0)
sdoc (~> 0.4.0)
sqlite3
turbolinks
tzinfo-data
uglifier (>= 1.3.0)
web-console (~> 2.0)
will_paginate
RUBY VERSION
ruby 2.1.8p440
BUNDLED WITH
1.12.5

113
ruby-backend/Guardfile Normal file
View file

@ -0,0 +1,113 @@
# A sample Guardfile
# More info at https://github.com/guard/guard#readme
## Uncomment and set this to only include directories you want to watch
# directories %w(app lib config test spec features)
## Uncomment to clear the screen before every task
# clearing :on
## Guard internally checks for changes in the Guardfile and exits.
## If you want Guard to automatically start up again, run guard in a
## shell loop, e.g.:
##
## $ while bundle exec guard; do echo "Restarting Guard..."; done
##
## Note: if you are using the `directories` clause above and you are not
## watching the project directory ('.'), then you will want to move
## the Guardfile to a watched dir and symlink it back, e.g.
#
# $ mkdir config
# $ mv Guardfile config/
# $ ln -s config/Guardfile .
#
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
guard :minitest, all_on_start:true do
=begin
####################### From RailsTutorial.org 3.42 #########################
watch(%r{^test/(.*)/?(.*)_test\.rb$})
watch('test/test_helper.rb') { 'test' }
watch('config/routes.rb') { integration_tests }
watch(%r{^app/models/(.*?)\.rb$}) do |matches|
"test/models/#{matches[1]}_test.rb"
end
watch(%r{^app/controllers/(.*?)_controller\.rb$}) do |matches|
resource_tests(matches[1])
end
watch(%r{^app/views/([^/]*?)/.*\.html\.erb$}) do |matches|
["test/controllers/#{matches[1]}_controller_test.rb"] +
integration_tests(matches[1])
end
watch(%r{^app/helpers/(.*?)_helper\.rb$}) do |matches|
integration_tests(matches[1])
end
watch('app/views/layouts/application.html.erb') do
'test/integration/site_layout_test.rb'
end
watch('app/helpers/sessions_helper.rb') do
integration_tests << 'test/helpers/sessions_helper_test.rb'
end
watch('app/controllers/sessions_controller.rb') do
['test/controllers/sessions_controller_test.rb',
'test/integration/users_login_test.rb']
end
watch('app/controllers/account_activations_controller.rb') do
'test/integration/users_signup_test.rb'
end
watch(%r{app/views/users/*}) do
resource_tests('users') +
['test/integration/microposts_interface_test.rb']
end
end
# Returns the integration tests corresponding to the given resource.
def integration_tests(resource = :all)
if resource == :all
Dir["test/integration/*"]
else
Dir["test/integration/#{resource}_*.rb"]
end
end
# Returns the controller tests corresponding to the given resource.
def controller_test(resource)
"test/controllers/#{resource}_controller_test.rb"
end
# Returns all tests for the given resource.
def resource_tests(resource)
integration_tests(resource) << controller_test(resource)
end
# with Minitest::Unit
### watch(%r{^test/(.*)\/?test_(.*)\.rb$})
### watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
### watch(%r{^test/test_helper\.rb$}) { 'test' }
# with Minitest::Spec
# watch(%r{^spec/(.*)_spec\.rb$})
# watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
# watch(%r{^spec/spec_helper\.rb$}) { 'spec' }
# Rails 4
# watch(%r{^app/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" }
# watch(%r{^app/controllers/application_controller\.rb$}) { 'test/controllers' }
# watch(%r{^app/controllers/(.+)_controller\.rb$}) { |m| "test/integration/#{m[1]}_test.rb" }
# watch(%r{^app/views/(.+)_mailer/.+}) { |m| "test/mailers/#{m[1]}_mailer_test.rb" }
# watch(%r{^lib/(.+)\.rb$}) { |m| "test/lib/#{m[1]}_test.rb" }
# watch(%r{^test/.+_test\.rb$})
# watch(%r{^test/test_helper\.rb$}) { 'test' }
# Rails < 4
# watch(%r{^app/controllers/(.*)\.rb$}) { |m| "test/functional/#{m[1]}_test.rb" }
# watch(%r{^app/helpers/(.*)\.rb$}) { |m| "test/helpers/#{m[1]}_test.rb" }
# watch(%r{^app/models/(.*)\.rb$}) { |m| "test/unit/#{m[1]}_test.rb" }
### end
=end
end

1
ruby-backend/Procfile Normal file
View file

@ -0,0 +1 @@
web: bundle exec puma -C config/puma.rb

44
ruby-backend/README.md Normal file
View file

@ -0,0 +1,44 @@
# HOW TO INSTALL
### Dependencies
###### Windows
- Install [Ruby](https://www.ruby-lang.org/fr/downloads/) (2.2.4)
- Install et init [Ruby Devkit](http://rubyinstaller.org/add-ons/devkit/)
###### macOs
```shell
# from terminal
brew update
brew install rbenv ruby-build postgresql # for libpq-fe
xcode-select --install # click, click, click
echo 'eval "$(rbenv init -)"' >> $HOME/.zshrc # assuming you're on zsh
source ~/.zshrc
```
### Project Init
```shell
# from terminal
git clone https://github.com/Tiqa/debats-api.git
cd debats-api
git checkout -b feat/api_mode origin/feat/api_mode
rbenv install 2.2.4
rbenv local 2.2.4 # or rbenv global 2.2.4
gem install bundler
gem install pg
#gem install nokogiri
bundler config build.nokogiri --use-system-libraries # macOS issue
bundler install
sudo gem install rails # on macOs
rbenv rehash
rails db:drop
rails db:create
rails db:migrate
rails db:seed
```
### Launch server
```shell
rails server
```
> server launched on port 3000

11
ruby-backend/README.rdoc Normal file
View file

@ -0,0 +1,11 @@
= Débats.fr
Ici présenter ce qu'est Débats.fr
== Comment participer ?
Ici aussi il faut expliquer
== Autre paragraphe
A alimenter

6
ruby-backend/Rakefile Normal file
View file

@ -0,0 +1,6 @@
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
Rails.application.load_tasks

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

View file

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View file

@ -0,0 +1,27 @@
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery.turbolinks
//= require jquery_ujs
//= require jquery-ui
//= require jquery.purr
//= require best_in_place
//= require best_in_place.purr
//= require autocomplete-rails
//= require bootstrap
//= require_tree .
//= require turbolinks
//= require jquery.jtruncate
//= require bootstrap-datepicker
//= require bootstrap-datepicker/locales/bootstrap-datepicker.fr
//= require fuelux

View file

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View file

@ -0,0 +1,5 @@
$(document).ready ->
$(".Autocomplete").bind('railsAutocomplete.select', ->
element = $(this).attr("data-id-element")
$(element).trigger("change")
)

View file

@ -0,0 +1,10 @@
$(document).ready(function () {
$(".Datepicker").datepicker({
format: "dd/mm/yyyy",
startView: 1,
todayBtn: "linked",
language: "fr",
autoclose: true,
todayHighlight: true
});
});

View file

@ -0,0 +1,4 @@
$ ->
$('input[data-dynamic-selectable-url][data-dynamic-selectable-target]').dynamicSelectable()
jQuery -> $('.best_in_place').best_in_place()

View file

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View file

@ -0,0 +1,33 @@
$.fn.extend
dynamicSelectable: ->
$(@).each (i, el) ->
new DynamicSelectable($(el))
class DynamicSelectable
constructor: ($select) ->
@init($select)
init: ($select) ->
@urlTemplate = $select.data('dynamicSelectableUrl')
@$targetSelect = $($select.data('dynamicSelectableTarget'))
$select.on 'change', =>
@clearTarget()
url = @constructUrl($select.val())
if url
$.getJSON url, (data) =>
$.each data, (index, el) =>
@$targetSelect.append "<option value='#{el.id}'>#{el.title}</option>"
# reinitialize target select
@reinitializeTarget()
else
@reinitializeTarget()
reinitializeTarget: ->
@$targetSelect.trigger("change")
clearTarget: ->
@$targetSelect.html('<option></option>')
constructUrl: (id) ->
if id && id != ''
@urlTemplate.replace(/:.+_id/, id)

View file

@ -0,0 +1,30 @@
$ ->
modal_holder_selector = '#modal-holder'
modal_selector = '.modal'
$(document).on 'click', 'a[data-modal]', ->
location = $(this).attr('href')
#Load modal dialog from server
$.get location, (data)->
$(modal_holder_selector).html(data).
find(modal_selector).modal()
wizard = $(".wizard").wizard()
wizard.on 'finished.fu.wizard', (e, data) ->
$("#addStatementModal").submit()
false
$(document).on 'ajax:success',
'form[data-modal]', (event, data, status, xhr)->
url = xhr.getResponseHeader('Location')
if url
# Redirect to url
window.location = url
else
# Remove old modal backdrop
$('.modal-backdrop').remove()
# Replace old modal with new one
$(modal_holder_selector).html(data).
find(modal_selector).modal()
false

View file

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View file

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View file

@ -0,0 +1,17 @@
$(document).ready ->
$("input#name").bind('change', ->
WikiPF = null
try ->
WikiPF = new WikipediaPublicFigure($(this).text)
catch
## Rien trouvé => ne rien faire
if WikiPF != null
ok = "ok"
## Afficher le bloc "Importer le contenu de la page Wikipedia "Nicolas Sarkozy" ?"
## Remplir d'abord nom, intro et photo
)

View file

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View file

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View file

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View file

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View file

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View file

@ -0,0 +1,28 @@
class Wikipedia
searchFor: (text) ->
# Code commun pour la recherche d'une page Wikipedia ?
class WikipediaPublicFigure extends Wikipedia
constructor: (name) ->
super()
@init(name)
init: ($select) ->
# Ici code scraping page Wikipedia de la personnalité et remplissage
# Si rien trouvé exception
@fullName = ""
@intro = ""
@photoUrl = ""
getFullName: ->
return @fullName
getIntro: ->
return @intro
getPhotoUrl: ->
return @photoUrl

View file

@ -0,0 +1,3 @@
// Place all the styles related to the AccountActivations controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View file

@ -0,0 +1,18 @@
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
* compiled file so the styles you add here take precedence over styles defined in any styles
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
* file per style scope.
*
*= require_tree .
*= require_self
*= require jquery-ui
*= require bootstrap-datepicker3
*= require fuelux
*/

View file

@ -0,0 +1,3 @@
// Place all the styles related to the Argument controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View file

@ -0,0 +1,3 @@
// Place all the styles related to the Autocomplete controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View file

@ -0,0 +1,5 @@
@mixin box_sizing {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}

View file

@ -0,0 +1 @@
$light-gray: #777;

View file

@ -0,0 +1,7 @@
.alert.alert-danger {
background-color: #fde4de;
border-color: #ccc;
color: #f21e40;
border: 1px solid #ccc;
border-radius: 0px;
}

View file

@ -0,0 +1,40 @@
.btn.btn-primary {
background-color: #fff; /* White */
font-family: 'Gotham-Bold', sans-serif;
border: 1px solid #ccc;
color: #ccc;
padding: 6px 12px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 12px;
letter-spacing: 1px;
text-transform: uppercase;
-webkit-transition-duration: 0.4s; /* Safari */
transition-duration: 0.4s;
}
.btn.btn-primary:hover {
background-color: #f21e40; /* Red débats */
border: 1px solid #f21e40;
color: white;
}
.btn.btn-danger {
background-color: #fff; /* White */
font-family: 'Gotham-Bold', sans-serif;
border: 1px solid #ccc;
color: #ccc;
padding: 6px 12px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 12px;
letter-spacing: 1px;
text-transform: uppercase;
-webkit-transition-duration: 0.4s; /* Safari */
transition-duration: 0.4s;
}
.btn.btn-danger:hover {
background-color: #000; /* Black */
border: 1px solid #000;
color: white;
}

View file

@ -0,0 +1,179 @@
@import "bootstrap-sprockets";
@import "bootstrap";
@import "mixins";
/* Universal */
body {
padding-top: 60px;
}
section {
overflow: auto;
}
textarea {
resize: vertical;
}
.center {
text-align: center;
h1 {
margin-bottom: 10px;
}
}
div.main-content {
min-height: 300px;
/* margin-top: 30px; */
}
/* forms */
input, textarea, select, .uneditable-input {
border: 1px solid #bbb;
width: 100%;
margin-bottom: 15px;
@include box_sizing;
}
input {
height: auto !important;
}
#error_explanation {
color: red;
ul {
color: red;
margin: 0 0 30px 0;
}
}
.field_with_errors {
@extend .has-error;
.form-control {
color: $state-danger-text;
}
}
.checkbox {
margin-top: -10px;
margin-bottom: 10px;
span {
margin-left: 20px;
font-weight: normal;
}
}
statements {
list-style-type: none;
}
div#last-statements {
float:right;
margin-right:10px;
.public-figure-little-image {
width: 50px;
height: 50px;
border-radius: 50%;
float:left;
margin-right:15px;
}
.public-figure-text {
overflow:hidden;}
}
a:link, a:visited {
color: #333333;
text-decoration: none;
}
a:hover, a:visited:hover
{
color: #333333;
text-decoration: none;
}
.morepersonalities {
color:#f21e40 !important;
vertical-align:middle;
text-align:center;
margin-right:15px;
}
.thumbpersonalities {
height:40px;
width: 40px;
-webkit-border-radius: 50%;
border-radius: 50%;
float:right;
margin-right:15px;
}
h6.count {
color:#f21e40 !important;
text-transform: lowercase;
}
.table>tbody>tr>td.seemore {
vertical-align: middle;
}
.seemore a:link, .seemore a:visited {
color:#f21e40 !important;
text-decoration:none !important;
}
.seemore a:hover, .seemore a:visited:hover {
color:#f21e40 !important;
text-decoration:none !important;
}
ul {
list-style-type: none;
}
#last-statements h2 {
font-weight:bold;
text-align:center;
}
.subjects-home {
margin-bottom:20px;
margin-top: 20px;
border-right: 1px solid #ccc;
padding-right: 20px;
}
.subjects-index {
padding-right: 20px;
}
.public-figures-index {
padding-right: 20px;
border-right: 1px solid #ccc;
}
a.morelink:link, a.morelink:visited {
color:#f21e40 !important;
text-decoration:none !important;
}
a.morelink:hover, a.morelink:visited:hover {
color:#f21e40 !important;
text-decoration:none !important;
}
.publicfigurehead {
display: inline-block;
}
.publicfigurethumb {
height:120px;
width: 120px;
-webkit-border-radius: 50%;
border-radius: 50%;
}
.publicfiguredescription {
display: inline-block;
}

View file

@ -0,0 +1,15 @@
@import "bootstrap-sprockets";
@import "bootstrap";
@import "mixins";
/* mixins, variables, etc. */
$gray-medium-light: #eaeaea;
.debug_dump {
clear: both;
float: left;
width: 100%;
margin-top: 45px;
@include box_sizing;
}

View file

@ -0,0 +1,32 @@
/* footer */
footer {
clear:left;
margin-top: 55px;
padding-top: 5px;
border-top: 1px solid #eaeaea;
color: #777;
a {
color: #555;
font-family: 'Gotham-Book', sans-serif;
&:hover {
color: #222;
font-family: 'Gotham-Book', sans-serif;
}
}
small {
float: left;
}
ul {
float: right;
list-style: none;
li {
float: left;
margin-left: 15px;
}
}
}

View file

@ -0,0 +1,80 @@
/* header */
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,600,600italic);
#logo {
float: left;
margin-right: 10px;
font-size: 1.7em;
font-family: 'Gotham-Book',"Helvetica Neue",Helvetica,Arial,sans-serif;
color: #f21e40;
text-transform: uppercase;
letter-spacing: 1px;
padding-top: 9px;
font-weight: bold;
}
#logo img {
width: 125px;
}
.navbar-custom {
margin-bottom: 20px;
border-bottom: 1px solid rgba(255,255,255,.3);
text-transform: uppercase;
font-family: 'Gotham-Bold',"Helvetica Neue",Helvetica,Arial,sans-serif;
letter-spacing: 1px;
background-color: #fff;
}
.navbar-custom .navbar-brand {
font-weight: 700;
}
.navbar-custom .navbar-brand:focus {
outline: 0;
}
.navbar-custom .navbar-brand .navbar-toggle {
padding: 4px 6px;
font-size: 16px;
color: #fff;
}
.navbar-custom .navbar-brand .navbar-toggle:focus,
.navbar-custom .navbar-brand .navbar-toggle:active {
outline: 0;
}
.navbar-custom a {
color: #f21e40;
}
.navbar-custom .nav li a {
-webkit-transition: background .3s ease-in-out;
-moz-transition: background .3s ease-in-out;
transition: background .3s ease-in-out;
}
.navbar-custom .nav li a:hover {
outline: 0;
color: #333;
background-color: transparent;
}
.navbar-custom .nav li a:focus,
.navbar-custom .nav li a:active {
outline: 0;
background-color: transparent;
}
.navbar-custom .nav li.active {
outline: 0;
}
.navbar-custom .nav li.active a {
color: #333;
background-color: rgba(255,255,255,.3);
}
.navbar-custom .nav li.active a:hover {
color: #f21e40;
}

View file

@ -0,0 +1,9 @@
.panel-group .panel {
border-radius: 0px;
border: 0px solid transparent;
box-shadow: 0px 0px rgba(0, 0, 0, 0.05);
}
.panel-default > .panel-heading {
background-color: #ffffff;
}

View file

@ -0,0 +1,10 @@
.purr {
position: fixed;
top: 30px;
right: 100px;
width: 250px;
padding: 20px;
background-color: #FCC;
border: solid 2px #666;
&:first-letter { text-transform: uppercase };
}

View file

@ -0,0 +1,92 @@
/* typography */
@import "variables";
@font-face {
font-family: 'Gotham-Book';
src:font-url('Gotham-Book.woff') format('woff');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Gotham-Bold';
src:font-url('Gotham-Bold.woff') format('woff');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Gotham-BookItalic';
src:font-url('Gotham-BookItalic.woff') format('woff');
font-weight: normal;
font-style: normal;
}
h1, h2, h3, h4, h5, h6 {
line-height: 1;
}
h1 {
font-family: 'Gotham-Book', sans-serif;
font-size: 3em;
letter-spacing: -2px;
margin-bottom: 30px;
text-align: center;
text-transform: uppercase;
color: #f21e40;
&:active {
color: #222;
}
}
h2 {
font-family: 'Gotham-Book', sans-serif;
font-size: 1.2em;
letter-spacing: -1px;
margin-bottom: 30px;
text-align: center;
font-weight: normal;
color: $light-gray;
text-transform: uppercase;
color: #f21e40;
&:active {
color: #222;
}
}
h5 {
font-family: 'Gotham-Bold', sans-serif;
font-size: 3em;
letter-spacing: 1px;
margin-bottom: 30px;
text-align: center;
text-transform: uppercase;
color: #FFFFFF;
font-weight: bold;
text-shadow: 0px 0px 5px rgba(0, 115, 162, 1);
}
p {
font-family: 'Gotham-Book', sans-serif;
font-size: 1.1em;
line-height: 1.7em;
text-align: justify;
}
#white {
font-family: 'Gotham-Book', sans-serif;
font-size: 1.1em;
line-height: 1.7em;
text-align: center;
color: #FFFFFF;
text-shadow: 0px 0px 30px rgba(0, 115, 162, 1);
}
#last-statements {
font-family: 'Gotham-Book', sans-serif;
font-size: 1.0em;
line-height: 1.4em;
list-style-type: none;
text-align: justify;
}

View file

@ -0,0 +1,10 @@
// Place all the styles related to the home controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
// Last statements on the left
div#subject-list {
float:left;
margin-right:10px;
}

View file

@ -0,0 +1,14 @@
.fuelux .modal .wizard > .actions {
position: inherit;
}
.modal-content {
background-color: #fff;
border: 1px solid #f21e40;
border-radius: 0px;
box-shadow: 0px 0px rgba(0, 0, 0, 0.5);
}
.form-control {
border: 1px solid #ccc;
border-radius: 0px;
}

View file

@ -0,0 +1,3 @@
// Place all the styles related to the PasswordResets controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View file

@ -0,0 +1,3 @@
// Place all the styles related to the Positions controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View file

@ -0,0 +1,55 @@
// Place all the styles related to the public-figures controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
#public_figure div {
height: 150px;
width: 100px;
-webkit-border-radius: 50%;
border-radius: 50%;
background-size:cover;
background-repeat:no-repeat;
}
h1 {
font-family: 'Gotham-Bold', sans-serif;
font-size: 1.5em !important ;
letter-spacing: 1px;
margin-bottom: 30px;
text-align: center;
text-transform: uppercase;
color: #f21e40;
&:active {
color: #222;
}
}
h2 {
font-family: 'Gotham-Book', sans-serif;
font-size: 1.2em;
letter-spacing: 1px;
margin-bottom: 30px;
text-align: center;
font-weight: normal;
color: lightgray;
text-transform: uppercase;
color: #f21e40;
&:active {
color: #222;
}
}
p {
font-family: 'Gotham-Book', sans-serif;
font-size: 1.1em;
line-height: 1.7em;
}
.btn {
border-radius: 0px;
padding: 4px 8px;
font-size: 12px;
}
.btn-primary {
color: #616161;
background-color: #fff;
border-color: #ededea;
}

View file

@ -0,0 +1,4 @@
#session_remember_me {
width: auto;
margin-left: 0;
}

View file

@ -0,0 +1,3 @@
// Place all the styles related to the PositionsStatements controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View file

@ -0,0 +1,10 @@
// Place all the styles related to the StaticPages controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
#reputation {
font-family: 'Gotham-Book';
src:font-url('Gotham-Book.woff') format('woff');
font-weight: normal;
font-style: normal;
font-size: 1.0em;
}

View file

@ -0,0 +1,28 @@
h1 {
text-align: left;
font-size: 2.5em;
}
h2 {
text-align: left;
}
img.subject-main-image {
float: right;
margin-right: 10px;
margin: 10px;
}
p.subject-presentation-text {
margin: 10px;
text-align: justify;
}
div.subjects-index {
ul li {
}
img.subject-main-image {
float:left;
}
}

View file

@ -0,0 +1,36 @@
/* sidebar */
aside {
section.user_info {
margin-top: 20px;
}
section {
padding: 10px 0;
margin-top: 20px;
&:first-child {
border: 0;
padding-top: 0;
}
span {
display: block;
margin-bottom: 3px;
line-height: 1;
}
h1 {
font-size: 1.4em;
text-align: left;
letter-spacing: -1px;
margin-bottom: 3px;
margin-top: 0px;
}
}
}
.gravatar {
float: left;
margin-right: 10px;
}
.gravatar_edit {
margin-top: 15px;
}

View file

@ -0,0 +1,20 @@
class AccountActivationsController < ApplicationController
def edit
user = User.find_by_email(params[:email])
if user && !user.activated && user.authenticated?(:activation, params[:id])
user.activate
log_in(user)
flash[:success] = "Votre compte a été activé. "
redirect_to user
else
if user && user.activated? # User already activated
flash[:warning] = "Votre compte a déjà été activé. "
else # Non-existent user with this e-mail or invalid token
flash[:danger] = "Lien d'activation incorrect. "
end
redirect_to root_url
end
end
end

View file

@ -0,0 +1,37 @@
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
include ApplicationHelper
include SessionsHelper
include ActionView::Helpers::TextHelper
before_action :set_locale
def respond_modal_with(*args, &blk) #TODO blk ?
options = args.extract_options!
options[:responder] = Responders::ModalResponder
respond_with *args, options, &blk
end
private
# Before Filters
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
## Adding locale to URLs
##def default_url_options (options = {})
#{locale: I18n.locale}.merge options
## end
# only if logged in
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Vous devez être identifié."
redirect_to login_url
end
end
end

View file

@ -0,0 +1,31 @@
class ArgumentsController < ApplicationController
before_action :auth_to_create, only: :create
def create
@argument = Argument.new(argument_params)
respond_to do |format|
if @argument.save
format.html { redirect_to root_url }
format.json {render json: @argument}
else
format.html { redirect_to root_url}
format.json { render json: @argument.errors }
end
end
end
private
def argument_params
params.permit(:name)
end
def auth_to_create
if ! redirect_not_logged_with_message "Vous devez être identifié pour créer un argument"
if ! allowed_to? :add_argument
render text: "Vous n'avez pas assez de réputation pour ajouter un argument", status: 500
end
end
end
end

View file

@ -0,0 +1,18 @@
class AutocompleteController < ApplicationController
autocomplete :subject, :title, full: true, extra_data: [:presentation]
autocomplete :public_figure, :name, full: true
def autocomplete_position_title
term = params[:term]
subject_id = params[:subject_id]
positions = Position
.where(subject_id: subject_id)
.where("title LIKE ?", "%#{term}%")
.order(:title)
.all
render json: positions.map { |position| { id: position.id, title: position.title, value: position.title } }
end
end

View file

@ -0,0 +1,7 @@
class HomeController < ApplicationController
def home
@subjects = Subject.paginate(page: params[:page])
@public_figures = PublicFigure.paginate(page: params[:page])
@latest_statements = Statement.latest
end
end

View file

@ -0,0 +1,56 @@
class PasswordResetsController < ApplicationController
before_action :valid_user, only:[:edit, :update]
before_action :check_expiration, only:[:edit, :update]
def new
end
def create
@user = User.find_by_email(params[:password_reset][:email].downcase)
if @user
@user.create_reset_digest
@user.send_password_reset_email
flash[:info] = "Un e-mail vous a été envoyé. Veuillez en suivre les instructions pour créer un nouveau mot de passe. "
redirect_to root_url
else
flash.now[:danger] = "Aucun utilisateur avec cette adresse e-mail. Veuillez vérifier votre saisie. "
render "new"
end
end
def edit
if (!@user.activated?)
@user.activate
end
end
def update
if params[:user][:password].blank?
flash.now[:danger] = "Vous devez choisir un mot de passe"
render "edit"
elsif @user.update_attributes(params.require(:user).permit(:password, :password_confirmation))
log_in @user
flash[:success] = "Nouveau mot de passe enregistré !"
redirect_to @user
else # Could not save new password (check validations)
render "edit"
end
end
private
def valid_user
@user = User.find_by_email(params[:email])
if (!@user || !@user.authenticated?(:reset, params[:id]))
flash[:danger] = "Lien incorrect."
redirect_to root_url
end
end
def check_expiration
if @user.password_reset_expired?
flash[:danger] = "Lien expiré. Veuillez renouveller votre demande. "
redirect_to new_password_reset_url
end
end
end

View file

@ -0,0 +1,48 @@
class PositionsController < ApplicationController
before_action :logged_in_user, only: [:create, :update, :destroy]
before_action :existing, only: [:update, :destroy]
def create
@subject = Subject.find_by_id(position_params[:subject_id])
if @subject
@position = @subject.positions.build(position_params)
if @position.save
flash[:success] = "Position ajoutée !"
else
flash[:danger] = pluralize(@position.errors.count, "erreur") + " : " + @position.errors.full_messages.join(", ")
end
redirect_to subject_url(@subject)
end
end
def index
@positions = Position.where(subject_id: params[:subject_id]).order(:title).all
respond_to do |format|
format.json { render json: @positions }
end
end
def update
end
def destroy
@subject = @position.subject
@position.destroy
flash[:success] = "Position supprimée !"
redirect_to request.referrer || @subject
end
private
def position_params
params.require(:position).permit(:title, :description, :subject_id)
end
def existing
@position = Position.find_by id:params[:id]
redirect_to root_url if @position.nil?
end
end

View file

@ -0,0 +1,81 @@
class PublicFiguresController < ApplicationController
respond_to :html, :json
before_action :find_public_figure, only: :show
before_action :check_reputation_to_destroy, only: :destroy
before_action :check_reputation_to_add, only: [:new, :create]
def index
@public_figures = PublicFigure.paginate(page: params[:page])
@latest_statements = Statement.latest
end
def show
@public_figure = PublicFigure.find(params[:public_figure_id])
@new_statement = @public_figure.statements.build
@latest_statements = Statement.latest
end
def new
@public_figure = PublicFigure.new
respond_modal_with @public_figure
end
def create
@public_figure = PublicFigure.new(public_figure_params)
if @public_figure.save
flash[:success] = "Personnalité \"#{@public_figure.name}\" référencée ! "
redirect_to @public_figure
else
render "new"
end
end
def destroy
public_figure = PublicFigure.find(params[:public_figure_id])
name = public_figure.name
public_figure.destroy #TODO Mark deleted instead of really deleting record
flash[:success] = "\"#{name}\" supprimé"
redirect_to public_figures_url
end
private
def public_figure_params
params.require(:public_figure).permit(:name, :presentation, :picture)
end
def check_reputation_to_destroy
if !current_user
store_location
flash[:danger] = "Vous devez être identifié pour supprimer une personnalité"
redirect_to login_url
else
@public_figure = PublicFigure.find(params[:public_figure_id])
if @public_figure.major? && !allowed_to?(:delete_major_personality) ||
@public_figure.minor? && !allowed_to?(:delete_minor_personality)
flash[:danger] = "Vous n'avez pas assez de réputation pour supprimer une personnalité"
redirect_to(PublicFigure.find(params[:public_figure_id]))
end
end
end
def check_reputation_to_add
if !current_user
store_location
flash[:danger] = "Vous devez être identifié pour ajouter une personnalité"
redirect_to login_url
elsif !allowed_to? :add_personality
flash[:danger] = "Vous n'avez pas assez de réputation pour ajouter une personnalité"
redirect_to public_figures_url
end
end
def find_public_figure
@public_figure = PublicFigure.find params[:public_figure_id]
if request.path != public_figure_path(@public_figure) # If old URL
redirect_to @public_figure, status: :moved_permanently # Redirect to new URL
end
end
end

View file

@ -0,0 +1,21 @@
class SessionsController < ApplicationController
def new
end
def create
@user = User.find_by_email(params[:session][:email].downcase.strip)
if @user && @user.authenticate(params[:session][:password])
log_in @user
params[:session][:remember_me] == "1" ? remember(@user) : forget(@user)
redirect_back_or @user
else
flash.now[:danger] = "Veuillez vérifier votre courriel et/ou votre mot de passe"
render "new"
end
end
def destroy
log_out if logged_in?
redirect_to root_path
end
end

View file

@ -0,0 +1,64 @@
class StatementsController < ApplicationController
respond_to :html, :json
before_action :logged_in_user, only: [:create, :update, :destroy]
def new
if params.include? :subject_id
@subject = Subject.find params[:subject_id]
@new_statement = @subject.statements.build
elsif params.include? :public_figure_id
@public_figure = PublicFigure.find params[:public_figure_id]
@new_statement = @public_figure.statements.build
else
@new_statement = Statement.new
end
respond_modal_with @new_statement
end
def create
@position = Position.find_by_id(statement_params[:position_id])
@public_figure = PublicFigure.find_by_id(statement_params[:public_figure_id])
if @position && @public_figure
@statement = @position.statements.build(statement_params)
@evidence = @statement.evidences.build(statement_evidence_params)
if @evidence.valid? && @statement.valid?
if @statement.save && @evidence.save
flash[:success] = "Prise de position et preuve enregistrées !"
else
flash[:danger] = pluralize( @statement.errors.count + @evidence.errors.count , "erreur") + " : " +
(@statement.errors.full_messages + @evidence.errors.full_messages).join(", ")
end
else
flash[:danger] = pluralize( @statement.errors.count + @evidence.errors.count , "erreur") + " : " +
(@statement.errors.full_messages + @evidence.errors.full_messages).join(", ")
end
else
flash[:danger] = "Une prise de position doit correspondre à une personnalité et à une position. "
end
redirect_to request.referrer || @position
end
def update
end
def destroy
end
private
def statement_params
params.require(:statement).permit(:position_id, :public_figure_id)
end
def statement_evidence_params
params.require(:statement).require(:evidence).permit(:title, :url, :file, :evidence_date, :fact_date)
end
end

View file

@ -0,0 +1,14 @@
class StaticPagesController < ApplicationController
def a_propos
end
def contact
end
def mode_demploi
end
end

View file

@ -0,0 +1,103 @@
class SubjectsController < ApplicationController
before_action :find_subject, only: :show
before_action :auth_to_create, only: :create
before_action :auth_to_edit, only: :edit
before_action :auth_to_destroy, only: :destroy
before_action :auth_to_update, only: :update
def index
@subjects = Subject.paginate(page: params[:page])
@latest_statements = Statement.latest
end
def show
@new_position = @subject.positions.build
respond_to do |format|
format.html
format.json {render json: @subject}
end
end
def new
@subject = Subject.new
end
def create
@subject = Subject.new(subject_params)
if @subject.save
flash[:success] = "Sujet \"#{@subject.title}\" créé ! "
redirect_to @subject
else
render "new"
end
end
def update
@subject = Subject.find(params[:subject_id])
respond_to do |format|
if @subject.update(subject_params)
grant_reputation_for!(:edited_subject)
format.html {redirect_to @subject}
format.json {respond_with_bip @subject }
else
format.html {render action: :edit}
format.json {respond_with_bip @subject }
end
end
end
def destroy
subject = Subject.find(params[:subject_id])
title = subject.title
subject.destroy
flash[:success] = "Sujet \"#{title}\" supprimé"
redirect_to subjects_url
end
private
def subject_params
params.require(:subject).permit(:title, :presentation, :problem, :picture)
end
def auth_to_update
redirect_not_logged_with_message "Vous devez être identifié pour éditer un sujet"
if ! allowed_to? :edit_minor_subject
flash[:danger] = "Vous n'avez pas assez de réputation pour éditer un sujet"
redirect_to(Subject.find(params[:subject_id]))
end
end
def auth_to_create
redirect_not_logged_with_message "Vous devez être identifié pour référencer un sujet"
if ! allowed_to? :add_subject
flash[:danger] = "Vous n'avez pas assez de réputation pour référencer un sujet"
redirect_to(Subject.find(params[:subject_id]))
end
end
def auth_to_edit
redirect_not_logged_with_message "Vous devez être identifié pour éditer un sujet"
if ! allowed_to? :edit_subject
flash[:danger] = "Vous n'avez pas assez de réputation pour éditer un sujet"
redirect_to(Subject.find(params[:subject_id]))
end
end
def auth_to_destroy
redirect_not_logged_with_message "Vous devez être identifié pour supprimer un sujet"
@subject = Subject.find(params[:subject_id])
if @subject.major? && !allowed_to?(:delete_major_subject) ||
@subject.minor? && !allowed_to?(:delete_minor_subject)
flash[:danger] = "Vous n'avez pas assez de réputation pour supprimer un sujet"
redirect_to(Subject.find(params[:subject_id]))
end
end
def find_subject
@subject = Subject.find params[:subject_id]
if request.path != subject_path(@subject) # If old URL
redirect_to @subject, status: :moved_permanently # Redirect to new URL
end
end
end

View file

@ -0,0 +1,53 @@
class UsersController < ApplicationController
before_action :logged_in_user, only: [:edit, :update]
before_action :self_user, only: [:edit, :update]
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
@user.send_activation_email
log_in(@user)
flash[:success] = "Bienvenue #{@user.name} ! Veuillez consultez vos e-mails pour valider votre compte."
redirect_to @user
else
render "new"
end
end
def edit
@user = User.find_by(id: params[:id])
end
def update
@user = User.find_by(id: params[:id])
if @user.update_attributes(user_params)
flash[:success] = "Modifications enregistrées !"
redirect_to @user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
# Before Filters
# only if correct user
def self_user
@user = User.find(params[:id])
redirect_to root_url unless current_user?(@user)
end
end

View file

@ -0,0 +1,2 @@
module AccountActivationsHelper
end

View file

@ -0,0 +1,53 @@
module ApplicationHelper
# Returns the full title of the page
def full_title(page_title = '')
base_title = "".html_safe
base_title << APP_NAME_WITH_DOMAIN_EXT
if page_title.empty?
base_title
else
full = "".html_safe
full << page_title
full << " | "
full << base_title
full
end
end
def bootstrap_class_for_flash_type flash_type
{ success: "alert-success", error: "alert-danger", alert: "alert-warning", notice: "alert-info" }[flash_type] || flash_type.to_s
end
def flash_messages(opts = {})
flash.each do |msg_type, message|
concat(content_tag(:div, message, class: "alert alert-#{msg_type} fade in") do
concat content_tag(:button, 'X', class: "close", data: { dismiss: 'alert' })
concat message
end)
end
nil
end
def allowed_to?(action)
return false if current_user.nil?
min_rank = REPUTATION_CONFIG["can"][action.to_s]
if (min_rank)
min_reputation = REPUTATION_CONFIG["ranks"][min_rank]
return current_user.reputation >= min_reputation
else
# TODO log exception
return false
end
end
def grant_reputation_for!(action)
return if current_user.nil?
granted_reputation = REPUTATION_CONFIG["actions_to_reputation"][action.to_s]
if granted_reputation
current_user.reputation += granted_reputation
current_user.save
end
end
end

View file

@ -0,0 +1,2 @@
module ArgumentsHelper
end

View file

@ -0,0 +1,2 @@
module AutocompleteHelper
end

View file

@ -0,0 +1,2 @@
module HomeHelper
end

View file

@ -0,0 +1,2 @@
module PasswordResetsHelper
end

View file

@ -0,0 +1,2 @@
module PositionsHelper
end

View file

@ -0,0 +1,2 @@
module PublicFiguresHelper
end

View file

@ -0,0 +1,64 @@
module SessionsHelper
def log_in(user)
session[:user_id] = user.id
end
def current_user
if (user_id = session[:user_id])
@current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(:remember, cookies[:remember_token])
log_in user
@current_user = user
end
end
end
def current_user?(user)
user == current_user
end
def logged_in?
!current_user.nil?
end
def log_out
forget(current_user)
session.delete(:user_id)
@current_user = nil
end
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
def store_location
session[:forwarding_url] = request.url if request.get?
end
def redirect_back_or(default)
redirect_to(session[:forwarding_url] || default)
session.delete(:forwarding_url)
end
def redirect_not_logged_with_message(message)
if !current_user
store_location
flash[:danger] = message
redirect_to login_url
return true
end
return false
end
end

View file

@ -0,0 +1,2 @@
module StatementsHelper
end

View file

@ -0,0 +1,2 @@
module StaticPagesHelper
end

View file

@ -0,0 +1,2 @@
module SubjectsHelper
end

View file

@ -0,0 +1,9 @@
module UsersHelper
def gravatar_for(user, options = {size:80})
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{options[:size]}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end

View file

View file

@ -0,0 +1,4 @@
class ApplicationMailer < ActionMailer::Base
default from: MAIL_FROM_NO_REPLY_WITH_NAME
layout 'mailer'
end

View file

@ -0,0 +1,22 @@
class UserMailer < ApplicationMailer
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.user_mailer.account_activation.subject
#
def account_activation(user)
@user = user
mail to: user.email, subject: "Activation de votre compte #{APP_NAME}"
end
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.user_mailer.password_reset.subject
#
def password_reset(user)
@user = user
mail to: user.email, subject: "Création d'un nouveau mot de passe pour votre compte #{APP_NAME}"
end
end

View file

View file

@ -0,0 +1,9 @@
class Argument < ActiveRecord::Base
belongs_to :subject
has_many :argument_in_statements
has_many :statements, through: :argument_in_statements, source: :statement
validates :name, presence: true, length: {maximum: 100}
validates :description, length: {maximum: 100}
end

View file

@ -0,0 +1,6 @@
class ArgumentInStatement < ActiveRecord::Base
belongs_to :statement
belongs_to :argument
validates_uniqueness_of :argument_id, scope: :statement_id
end

View file

View file

@ -0,0 +1,19 @@
class Evidence < ActiveRecord::Base
belongs_to :statement
mount_uploader :file, PictureUploader
validates :statement, presence: true
validates :title, presence: true, length: {maximum: 100}
validates :fact_date, presence: true
validate :either_url_or_file
private
def either_url_or_file
if !url? && !file?
errors.add(:evidence_title, "Vous devez indiquer soit un lien Internet soit un fichier")
end
end
end

View file

@ -0,0 +1,17 @@
class Position < ActiveRecord::Base
belongs_to :subject
has_many :statements, dependent: :destroy
validates :subject, presence: true
validates :title, presence: true
validates :description, presence: true
validate :at_least_one_statement
private
def at_least_one_statement
if statements.length < 1
errors.add(:statements, "Il faut au moins une prise de position pour cette position")
end
end
end

View file

@ -0,0 +1,45 @@
class PublicFigure < ActiveRecord::Base
has_many :statements, dependent: :destroy
has_many :positions, through: :statements, source: :position
has_many :subjects, through: :positions, source: :subject
mount_uploader :picture, PictureUploader
## VALIDATION
validates_presence_of :name, :presentation
validates :name, length: {maximum: 100}, uniqueness: {case_sensitive: false}
validates :slug, length: {minimum: 3}, uniqueness: {case_sensitive: false}
validate :picture_size
# Friendly ID
extend FriendlyId
friendly_id :name, use: [:slugged, :finders, :history]
def should_generate_new_friendly_id?
name_changed? || super
end
def associated_subjects
statements # Statements of this personality
.reject(&:new_record?) # Ignore new records
.map(&:position) # get position of each statement
.map(&:subject) # get subject of each position
.uniq # dedupe
end
def major?
created_at > 1.week.ago || statements.size > 2
end
def minor?
!major?
end
private
def picture_size
if picture.size > 5.megabytes
errors.add(:picture, "L'image ne doit pas dépasser 5 Mo")
end
end
end

View file

@ -0,0 +1,28 @@
class Statement < ActiveRecord::Base
belongs_to :public_figure
belongs_to :position
has_one :subject, through: :position
has_many :evidences
has_many :argument_in_statements
validates_presence_of :position
validates_presence_of :public_figure
validate :at_least_one_evidence
class << self
def latest
Statement.order(id: :desc).limit(5)
end
end
private
def at_least_one_evidence
if evidences.reject(&:marked_for_destruction?).size < 1
errors.add(:evidences, "Il faut au moins une preuve de cette prise de position")
end
end
end

View file

@ -0,0 +1,50 @@
class Subject < ActiveRecord::Base
has_many :positions, dependent: :destroy
has_many :arguments, dependent: :destroy
has_many :statements, through: :positions, source: :statements
mount_uploader :picture, PictureUploader
## VALIDATIONS
validates_presence_of :title, :slug, :presentation, :problem
validates :title, length: {maximum: 100}, uniqueness: {case_sensitive: false}
validates :slug, length: {minimum: 3}, uniqueness: {case_sensitive: false}
validate :picture_size
# Friendly ID
extend FriendlyId
friendly_id :title, use: [:slugged, :finders, :history]
def should_generate_new_friendly_id?
title_changed? || super
end
def associated_public_figures
statements.map(&:public_figure).flatten
end
def get_positions_for_public_figure(public_figure)
#TODO performance optimization
statements # Liste des prises de position liées à ce sujet ...
.select { |s| s.public_figure == public_figure } # ... et à cette personnalité
.map(&:position) # On récupère la position de chacune de ces prises de positions
.uniq # Dedup
end
def major?
created_at > 1.week.ago || statements.size > 5
end
def minor?
!major?
end
private
def picture_size
if picture.size > 5.megabytes
errors.add(:picture, t("image_must_not_be_bigger_than", size: 5, unit:t("mb")))
end
end
end

View file

@ -0,0 +1,99 @@
class User < ActiveRecord::Base
attr_accessor :remember_token, :activation_token, :reset_token
## DEFAULT VALUES
after_initialize :default_values
## NAME VALIDATION
validates :name,
presence: true,
length: {maximum: 50}
validates :reputation,
presence: true
## EMAIL VALIDATION
VALID_EMAIL_REGEX =/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email,
presence: true,
length: {maximum: 255},
format: {with:VALID_EMAIL_REGEX},
uniqueness: {case_sensitive: false}
## PASSWORD MANAGEMENT
has_secure_password
## PASSWORD VALIDATION
validates :password, length: {minimum: 8}, allow_blank: true
## EMAIL ALWAYS IN DOWNCASE
before_save { self.email.downcase! }
## ACTIVATION DIGEST CREATION
before_create :create_activation_digest
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
# token matches the digest ?
def authenticated?(attribute, token)
digest = send("#{attribute}_digest")
return false if digest.nil?
BCrypt::Password.new(digest).is_password?(token)
end
# forget remembered session
def forget
update_attribute(:remember_digest, nil)
end
def send_activation_email
UserMailer.account_activation(self).deliver_now
end
def activate
update_columns(activated: true, activated_at: Time.zone.now)
end
def create_reset_digest
self.reset_token = User.new_token
update_columns(reset_digest: User.digest(reset_token), reset_sent_at: Time.zone.now)
end
def send_password_reset_email
UserMailer.password_reset(self).deliver_now
end
def password_reset_expired?
reset_sent_at < 2.hours.ago
end
private
def create_activation_digest
self.activation_token = User.new_token
self.activation_digest = User.digest(activation_token)
end
def default_values
self.reputation ||= 0
end
class << self
# Returns a digest
def digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
# Returns a random token.
def new_token
SecureRandom.urlsafe_base64
end
end
end

Some files were not shown because too many files have changed in this diff Show more