Skip to content
Browse files

All work until 17/10/2012 in one commit

This commit was obtained by squashing multiple initial commits on 2012-10-18.
  • Loading branch information...
0 parents commit 3573d584001c110555673169de10d0d4afc44625 @alexeymuranov committed
Showing with 7,266 additions and 0 deletions.
  1. +6 −0 .gitignore
  2. +47 −0 Gemfile
  3. +82 −0 Gemfile.lock
  4. +61 −0 Rakefile
  5. +763 −0 application.rb
  6. +12 −0 config.ru
  7. +25 −0 config/database.yml
  8. +57 −0 db/migrate/01_create_participants.rb
  9. +27 −0 db/migrate/02_create_talks.rb
  10. +21 −0 db/migrate/03_create_talk_proposals.rb
  11. +16 −0 db/migrate/04_create_hotels.rb
  12. +20 −0 db/migrate/05_create_accommodations.rb
  13. +16 −0 db/migrate/06_create_conference_dinner_reservations.rb
  14. +30 −0 helpers.rb
  15. +205 −0 internationalisation/defaults/en-GB.yml
  16. +205 −0 internationalisation/defaults/en-US.yml
  17. +205 −0 internationalisation/defaults/en.yml
  18. +222 −0 internationalisation/defaults/fr.yml
  19. +31 −0 internationalisation/emails/en.yml
  20. +31 −0 internationalisation/emails/fr.yml
  21. +81 −0 internationalisation/models/en.yml
  22. +81 −0 internationalisation/models/fr.yml
  23. +188 −0 internationalisation/views/en.yml
  24. +188 −0 internationalisation/views/fr.yml
  25. +61 −0 lib/attribute_constraints.rb
  26. +38 −0 lib/attribute_mutability.rb
  27. +44 −0 lib/attribute_types.rb
  28. +62 −0 lib/pseudo_columns.rb
  29. +270 −0 models.rb
  30. +26 −0 public_folder/404.html
  31. +26 −0 public_folder/422.html
  32. +36 −0 public_folder/css/blueprint/ie.css
  33. +29 −0 public_folder/css/blueprint/print.css
  34. +265 −0 public_folder/css/blueprint/screen.css
  35. +102 −0 public_folder/css/html5reset.css
  36. BIN public_folder/css/jquery-ui/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png
  37. BIN public_folder/css/jquery-ui/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
  38. BIN public_folder/css/jquery-ui/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
  39. BIN public_folder/css/jquery-ui/smoothness/images/ui-bg_glass_65_ffffff_1x400.png
  40. BIN public_folder/css/jquery-ui/smoothness/images/ui-bg_glass_75_dadada_1x400.png
  41. BIN public_folder/css/jquery-ui/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png
  42. BIN public_folder/css/jquery-ui/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
  43. BIN public_folder/css/jquery-ui/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png
  44. BIN public_folder/css/jquery-ui/smoothness/images/ui-icons_222222_256x240.png
  45. BIN public_folder/css/jquery-ui/smoothness/images/ui-icons_2e83ff_256x240.png
  46. BIN public_folder/css/jquery-ui/smoothness/images/ui-icons_454545_256x240.png
  47. BIN public_folder/css/jquery-ui/smoothness/images/ui-icons_888888_256x240.png
  48. BIN public_folder/css/jquery-ui/smoothness/images/ui-icons_cd0a0a_256x240.png
  49. +354 −0 public_folder/css/jquery-ui/smoothness/jquery-ui-1.8.21.custom.css
  50. BIN public_folder/css/jquery-ui/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png
  51. BIN public_folder/css/jquery-ui/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png
  52. BIN public_folder/css/jquery-ui/ui-lightness/images/ui-bg_flat_10_000000_40x100.png
  53. BIN public_folder/css/jquery-ui/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png
  54. BIN public_folder/css/jquery-ui/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png
  55. BIN public_folder/css/jquery-ui/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png
  56. BIN public_folder/css/jquery-ui/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png
  57. BIN public_folder/css/jquery-ui/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
  58. BIN public_folder/css/jquery-ui/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
  59. BIN public_folder/css/jquery-ui/ui-lightness/images/ui-icons_222222_256x240.png
  60. BIN public_folder/css/jquery-ui/ui-lightness/images/ui-icons_228ef1_256x240.png
  61. BIN public_folder/css/jquery-ui/ui-lightness/images/ui-icons_ef8c08_256x240.png
  62. BIN public_folder/css/jquery-ui/ui-lightness/images/ui-icons_ffd27a_256x240.png
  63. BIN public_folder/css/jquery-ui/ui-lightness/images/ui-icons_ffffff_256x240.png
  64. +354 −0 public_folder/css/jquery-ui/ui-lightness/jquery-ui-1.8.21.custom.css
  65. BIN public_folder/favicon.ico
  66. BIN public_folder/images/CNRSfilaire-grand.jpg
  67. BIN public_folder/images/bannerToulouse.jpg
  68. BIN public_folder/images/logo_cimi.jpg
  69. BIN public_folder/images/logo_imt-mixed.png
  70. BIN public_folder/images/logo_imt-transparent.png
  71. BIN public_folder/images/logo_imt.png
  72. BIN public_folder/images/logo_offi_imt.jpg
  73. BIN public_folder/images/logo_toulouse3.jpg
  74. BIN public_folder/images/logo_tresse.png
  75. BIN public_folder/images/logo_ups.png
  76. +4 −0 public_folder/js/jquery-1.7.2.min.js
  77. +9 −0 public_folder/js/jquery-ui-1.8.21.custom.min.js
  78. +59 −0 tests/tests.rb
  79. +12 −0 view_templates/_jquery_ui_for_forms.haml
  80. +31 −0 view_templates/email/_registration_details.haml
  81. +12 −0 view_templates/email/registration_confirmation.html.haml
  82. +6 −0 view_templates/email/registration_notification.html.haml
  83. +76 −0 view_templates/layout.haml
  84. +3 −0 view_templates/layout/_banner.haml
  85. +16 −0 view_templates/layout/_footer.haml
  86. +5 −0 view_templates/layout/_header.haml
  87. +6 −0 view_templates/layout/_language_selector.haml
  88. +15 −0 view_templates/layout/_main_menu.haml
  89. +15 −0 view_templates/layout/_main_menu_for_organisers.haml
  90. +5 −0 view_templates/layout/_title.haml
  91. +146 −0 view_templates/pages/_registration_form.haml
  92. +7 −0 view_templates/pages/accommodation.html.haml
  93. +7 −0 view_templates/pages/contacts.html.haml
  94. +7 −0 view_templates/pages/directions_to_get_here.html.haml
  95. +7 −0 view_templates/pages/funding.html.haml
  96. +7 −0 view_templates/pages/generic_page.html.haml
  97. +7 −0 view_templates/pages/index.html.haml
  98. 0 view_templates/pages/organiser_connexion/_hotel.haml
  99. 0 view_templates/pages/organiser_connexion/_hotel_form.haml
  100. +62 −0 view_templates/pages/organiser_connexion/_participant.haml
  101. +163 −0 view_templates/pages/organiser_connexion/_participant_form.haml
  102. +25 −0 view_templates/pages/organiser_connexion/_talk.haml
  103. +89 −0 view_templates/pages/organiser_connexion/_talk_form.haml
  104. +15 −0 view_templates/pages/organiser_connexion/delete_participant.html.haml
  105. +14 −0 view_templates/pages/organiser_connexion/delete_talk.html.haml
  106. 0 view_templates/pages/organiser_connexion/hotels.html.haml
  107. +27 −0 view_templates/pages/organiser_connexion/login.html.haml
  108. +9 −0 view_templates/pages/organiser_connexion/participants.html.haml
  109. +9 −0 view_templates/pages/organiser_connexion/talks.html.haml
  110. +7 −0 view_templates/pages/organising_committee.html.haml
  111. +12 −0 view_templates/pages/participants.html.haml
  112. +1 −0 view_templates/pages/poster.html.haml
  113. +7 −0 view_templates/pages/program.html.haml
  114. +3 −0 view_templates/pages/registration.html.haml
  115. +7 −0 view_templates/pages/scientific_committee.html.haml
  116. +7 −0 view_templates/pages/useful_links.html.haml
  117. +6 −0 view_templates/stylesheets/application.css.scss
  118. +39 −0 view_templates/stylesheets/bourbon/_bourbon.scss
  119. +273 −0 view_templates/stylesheets/bourbon/addons/_button.scss
  120. +29 −0 view_templates/stylesheets/bourbon/addons/_clearfix.scss
  121. +12 −0 view_templates/stylesheets/bourbon/addons/_font-face.scss
  122. +5 −0 view_templates/stylesheets/bourbon/addons/_font-family.scss
  123. +15 −0 view_templates/stylesheets/bourbon/addons/_hide-text.scss
  124. +36 −0 view_templates/stylesheets/bourbon/addons/_html5-input-types.scss
  125. +42 −0 view_templates/stylesheets/bourbon/addons/_position.scss
  126. +32 −0 view_templates/stylesheets/bourbon/addons/_timing-functions.scss
  127. +125 −0 view_templates/stylesheets/bourbon/css3/_animation.scss
  128. +3 −0 view_templates/stylesheets/bourbon/css3/_appearance.scss
  129. +57 −0 view_templates/stylesheets/bourbon/css3/_background-image.scss
  130. +11 −0 view_templates/stylesheets/bourbon/css3/_background-size.scss
  131. +56 −0 view_templates/stylesheets/bourbon/css3/_border-image.scss
  132. +42 −0 view_templates/stylesheets/bourbon/css3/_border-radius.scss
  133. +12 −0 view_templates/stylesheets/bourbon/css3/_box-shadow.scss
  134. +4 −0 view_templates/stylesheets/bourbon/css3/_box-sizing.scss
  135. +47 −0 view_templates/stylesheets/bourbon/css3/_columns.scss
  136. +52 −0 view_templates/stylesheets/bourbon/css3/_flex-box.scss
  137. +8 −0 view_templates/stylesheets/bourbon/css3/_inline-block.scss
  138. +43 −0 view_templates/stylesheets/bourbon/css3/_linear-gradient.scss
  139. +12 −0 view_templates/stylesheets/bourbon/css3/_prefixer.scss
  140. +76 −0 view_templates/stylesheets/bourbon/css3/_radial-gradient.scss
  141. +11 −0 view_templates/stylesheets/bourbon/css3/_transform.scss
  142. +72 −0 view_templates/stylesheets/bourbon/css3/_transition.scss
  143. +3 −0 view_templates/stylesheets/bourbon/css3/_user-select.scss
  144. +44 −0 view_templates/stylesheets/bourbon/functions/_deprecated-webkit-gradient.scss
  145. +35 −0 view_templates/stylesheets/bourbon/functions/_flex-grid.scss
  146. +13 −0 view_templates/stylesheets/bourbon/functions/_grid-width.scss
  147. +23 −0 view_templates/stylesheets/bourbon/functions/_linear-gradient.scss
  148. +40 −0 view_templates/stylesheets/bourbon/functions/_modular-scale.scss
  149. +62 −0 view_templates/stylesheets/bourbon/functions/_radial-gradient.scss
  150. +14 −0 view_templates/stylesheets/bourbon/functions/_render-gradients.scss
  151. +9 −0 view_templates/stylesheets/bourbon/functions/_tint-shade.scss
  152. +22 −0 view_templates/stylesheets/bourbon/functions/_transition-property-name.scss
  153. +6 −0 view_templates/stylesheets/bourbon/lib/bourbon.rb
  154. +6 −0 view_templates/stylesheets/bourbon/lib/bourbon/sass_extensions.rb
  155. +13 −0 view_templates/stylesheets/bourbon/lib/bourbon/sass_extensions/functions.rb
  156. +14 −0 view_templates/stylesheets/bourbon/lib/bourbon/sass_extensions/functions/compact.rb
  157. +249 −0 view_templates/stylesheets/custom.scss
  158. +66 −0 view_templates/stylesheets/experiments.scss
  159. +181 −0 view_templates/stylesheets/positions.scss
  160. +1 −0 view_templates/text/en/accommodation.md
  161. +7 −0 view_templates/text/en/contacts.md
  162. +3 −0 view_templates/text/en/directions_to_get_here.md
  163. +1 −0 view_templates/text/en/funding.md
  164. +17 −0 view_templates/text/en/index.md
  165. +1 −0 view_templates/text/en/invited_participants.md
  166. +1 −0 view_templates/text/en/organising_committee.md
  167. +1 −0 view_templates/text/en/poster.md
  168. +18 −0 view_templates/text/en/program.md
  169. +1 −0 view_templates/text/en/registration.md
  170. +3 −0 view_templates/text/en/registration_confirmation.md
  171. +11 −0 view_templates/text/en/scientific_committee.md
  172. +5 −0 view_templates/text/en/useful_links.md
  173. +1 −0 view_templates/text/fr/accommodation.md
  174. +7 −0 view_templates/text/fr/contacts.md
  175. +3 −0 view_templates/text/fr/directions_to_get_here.md
  176. +1 −0 view_templates/text/fr/funding.md
  177. +17 −0 view_templates/text/fr/index.md
  178. +1 −0 view_templates/text/fr/invited_participants.md
  179. +1 −0 view_templates/text/fr/organising_committee.md
  180. +1 −0 view_templates/text/fr/poster.md
  181. +18 −0 view_templates/text/fr/program.md
  182. +1 −0 view_templates/text/fr/registration.md
  183. +3 −0 view_templates/text/fr/registration_confirmation.md
  184. +11 −0 view_templates/text/fr/scientific_committee.md
  185. +5 −0 view_templates/text/fr/useful_links.md
6 .gitignore
@@ -0,0 +1,6 @@
+.bundle
+db/*.sqlite3
+log/*.log
+tmp/
+.DS_Store
+.sass-cache/
47 Gemfile
@@ -0,0 +1,47 @@
+source :rubygems
+
+# Rake (like "make"), to use Rakefile (Makefile for Ruby):
+gem 'rake'
+
+gem 'sinatra'
+
+group :test do
+ # Testing
+ gem 'rack-test'
+end
+
+group :development, :test do
+ # Web server (instead of WEBrick):
+ gem 'thin'
+end
+
+# Database interaction:
+gem 'activerecord'
+gem 'sqlite3'
+
+# HTML/CSS from templates:
+gem 'haml'
+gem 'redcarpet'
+gem 'sass'
+
+# Mixin library for Sass:
+gem 'bourbon'
+
+# Localizations:
+gem 'i18n'
+
+# Email:
+gem 'pony'
+
+# Session-based flash messages
+gem 'sinatra-flash'
+
+group :development do
+ # Ruby Debugger:
+ case RUBY_VERSION[0..2]
+ when '1.8'
+ gem 'ruby-debug'
+ when '1.9'
+ gem 'debugger'
+ end
+end
82 Gemfile.lock
@@ -0,0 +1,82 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ activemodel (3.2.8)
+ activesupport (= 3.2.8)
+ builder (~> 3.0.0)
+ activerecord (3.2.8)
+ activemodel (= 3.2.8)
+ activesupport (= 3.2.8)
+ arel (~> 3.0.2)
+ tzinfo (~> 0.3.29)
+ activesupport (3.2.8)
+ i18n (~> 0.6)
+ multi_json (~> 1.0)
+ arel (3.0.2)
+ bourbon (2.1.1)
+ sass (>= 3.1)
+ builder (3.0.3)
+ columnize (0.3.6)
+ daemons (1.1.9)
+ debugger (1.2.0)
+ columnize (>= 0.3.1)
+ debugger-linecache (~> 1.1.1)
+ debugger-ruby_core_source (~> 1.1.3)
+ debugger-linecache (1.1.2)
+ debugger-ruby_core_source (>= 1.1.1)
+ debugger-ruby_core_source (1.1.4)
+ eventmachine (1.0.0)
+ haml (3.1.7)
+ i18n (0.6.1)
+ mail (2.4.4)
+ i18n (>= 0.4.0)
+ mime-types (~> 1.16)
+ treetop (~> 1.4.8)
+ mime-types (1.19)
+ multi_json (1.3.6)
+ polyglot (0.3.3)
+ pony (1.4)
+ mail (> 2.0)
+ rack (1.4.1)
+ rack-protection (1.2.0)
+ rack
+ rack-test (0.6.2)
+ rack (>= 1.0)
+ rake (0.9.2.2)
+ redcarpet (2.2.1)
+ sass (3.2.1)
+ sinatra (1.3.3)
+ rack (~> 1.3, >= 1.3.6)
+ rack-protection (~> 1.2)
+ tilt (~> 1.3, >= 1.3.3)
+ sinatra-flash (0.3.0)
+ sinatra (>= 1.0.0)
+ sqlite3 (1.3.6)
+ thin (1.5.0)
+ daemons (>= 1.0.9)
+ eventmachine (>= 0.12.6)
+ rack (>= 1.0.0)
+ tilt (1.3.3)
+ treetop (1.4.11)
+ polyglot
+ polyglot (>= 0.3.1)
+ tzinfo (0.3.33)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ activerecord
+ bourbon
+ debugger
+ haml
+ i18n
+ pony
+ rack-test
+ rake
+ redcarpet
+ sass
+ sinatra
+ sinatra-flash
+ sqlite3
+ thin
61 Rakefile
@@ -0,0 +1,61 @@
+# encoding: UTF-8 (magic comment)
+
+require 'active_record'
+require 'active_support/core_ext/string/strip'
+# require 'fileutils'
+require 'rake/testtask'
+require_relative 'application'
+
+Rake::TestTask.new do |t|
+ t.pattern = "tests/*.rb"
+end
+
+namespace :db do
+ desc 'create an ActiveRecord migration in ./db/migrate'
+ task :create_migration do
+ name = ENV['NAME']
+ if name.nil?
+ raise 'No NAME specified. Example usage: `rake db:create_migration NAME=create_users`'
+ end
+
+ migrations_dir = File.join('db', 'migrate')
+ version = ENV['VERSION'] || Time.now.utc.strftime('%Y%m%d%H%M%S')
+ filename = "#{ version }_#{ name }.rb"
+ migration_class = name.split('_').map(&:capitalize).join
+
+ FileUtils.mkdir_p(migrations_dir)
+
+ File.open(File.join(migrations_dir, filename), 'w') do |file|
+ file.write <<-MIGRATION.strip_heredoc
+ class #{ migration_class } < ActiveRecord::Migration
+ def up
+ end
+
+ def down
+ end
+ end
+ MIGRATION
+ end
+ end
+
+ desc 'migrate the database (use version with VERSION=n)'
+ # NOTE: set 'RACK_ENV' environment variable to specify deployment
+ # environment (:-\)
+ # It can be 'development', 'test', 'production'.
+ # The default is usually 'development'.
+ # Example: rake RACK_ENV=test db:migrate
+ task :migrate do
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
+ ActiveRecord::Migration.verbose = true
+ version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
+ CTT2013.connect_database
+ ActiveRecord::Migrator.migrate('db/migrate', version)
+ end
+
+ desc 'rolls back the migration (use steps with STEP=n)'
+ task :rollback do
+ CTT2013.connect_database
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1
+ ActiveRecord::Migrator.rollback('db/migrate', step)
+ end
+end
763 application.rb
@@ -0,0 +1,763 @@
+# encoding: UTF-8 (magic comment)
+
+require 'rubygems'
+
+require 'bundler/setup'
+
+require 'sinatra/base'
+
+require 'set' # to use Set data structure
+
+require 'digest' # to hash passwords
+
+require 'yaml'
+
+class CTT2013 < Sinatra::Base
+
+ require 'active_record'
+ require 'logger'
+ require 'sqlite3'
+
+ require 'haml'
+ require 'sass'
+ require 'redcarpet' # Markdown
+
+ require 'pony' # Email
+
+ require 'i18n' # Internationalisation
+
+ require 'sinatra/flash' # Session-based flash
+
+ require 'debugger' if development? # for debugging
+
+ # Settings
+ # ========
+
+ # Host-specific constants
+ if production?
+ # For IMT web site
+ BASE_URL = '/top-geom-conf-2013/'
+ REQUEST_BASE_URL = '/'
+ # EMAIL_TO_ORGANISERS_BASIC_ATTRIBUTES =
+ # { :to => 'comb@math.univ-toulouse.fr',
+ # :from => 'no-reply.ctt2013-registration@math.univ-toulouse.fr',
+ # :via => :smtp }
+ EMAIL_TO_ORGANISERS_BASIC_ATTRIBUTES =
+ { :to => 'muranov@math.univ-toulouse.fr',
+ :from => 'no-reply.ctt2013-registration@math.univ-toulouse.fr',
+ :via => :smtp }
+ EMAIL_TO_PARTICIPANT_BASIC_ATTRIBUTES =
+ { :from => 'no-reply.ctt2013-registration@math.univ-toulouse.fr',
+ :reply_to => 'comb@math.univ-toulouse.fr',
+ :via => :smtp }
+ else
+ # For localhost
+ REQUEST_BASE_URL = BASE_URL = '/'
+ EMAIL_TO_ORGANISERS_BASIC_ATTRIBUTES =
+ { :to => "#{ ENV['USER'] }@localhost",
+ :from => 'no-reply@localhost',
+ :via => :sendmail }
+ EMAIL_TO_PARTICIPANT_BASIC_ATTRIBUTES =
+ { :from => 'no-reply@localhost',
+ :reply_to => 'comb@math.univ-toulouse.fr',
+ :via => :sendmail }
+ end
+
+ configure do
+ set :app_file, __FILE__
+ set :root, File.dirname(__FILE__)
+ set :views, File.join(settings.root, 'view_templates')
+ set :public_folder, File.join(settings.root, 'public_folder')
+
+ set :method_override, true # enable the POST _method hack
+
+ # Enable/disable cookie based sessions
+ # enable for flash messages in registration form and authentication
+ set :sessions, :path => BASE_URL
+
+ # set :bind, 'localhost' # server hostname or IP address
+ # set :port, 4567 # server port
+ # set :lock, true # ensure single request concurrency with a mutex lock
+ end
+
+ # Authentication
+ # --------------
+
+ class User
+ attr_reader :username, :role
+ attr_writer :password_hash
+
+ def initialize(username, role = nil)
+ @username, @role = username, role
+ (@@users ||= Set.new) << self
+ end
+
+ def set_password(password)
+ @password_hash = Digest::SHA2.base64digest(password)
+ end
+
+ def accept_password?(password)
+ @password_hash == Digest::SHA2.base64digest(password)
+ end
+
+ def id
+ object_id
+ end
+
+ def self.each
+ block_given? ? @@users.each { |u| yield(u) } : @@users.each
+ end
+
+ def self.find_by_username(username)
+ @@users.find { |u| u.username == username }
+ end
+
+ def self.find(id)
+ @@users.find { |u| u.id == id }
+ end
+ end
+
+ User.new('comb', 'organiser').password_hash =
+ '6nKIQNNx4aVW9R5XQT/okSB6JcH3Sbb3b88Gjz5Nyt0='
+
+ User.new('gestion', 'main_organiser').password_hash =
+ 'fqTJyyW7Hg2d90NkzmRPOVSb54LlxgeGMDxF6nmNRt8='
+
+ # Internationalisation
+ # --------------------
+
+ LOCALES = [:en, :fr]
+ DEFAULT_LOCALE = :fr
+
+ I18n.load_path =
+ Dir[::File.join(settings.root, 'internationalisation/**/*.{rb,yml}')]
+ I18n.default_locale = DEFAULT_LOCALE
+
+ # Sass
+ # ----
+
+ # Needed for Bourbon SCSS library to be used correctly by `scss`:
+ require ::File.join(settings.views, 'stylesheets/bourbon/lib/bourbon')
+
+ # Custom sass functions
+ #
+ module ::Sass::Script::Functions
+ def banner_url
+ ::Sass::Script::String.new(
+ "url('#{ BASE_URL }images/bannerToulouse.jpg');"
+ )
+ end
+ end
+
+ # Sessions
+ # --------
+
+ # Session-based flash
+ register Sinatra::Flash
+
+ # ActiveRecord
+ # ------------
+
+ def self.connect_database(environment = settings.environment)
+ ActiveRecord::Base.logger = Logger.new("log/#{ environment }.log")
+ ActiveRecord::Base.configurations = YAML::load(IO.read('config/database.yml'))
+ ActiveRecord::Base.establish_connection(environment)
+ end
+
+ # Models
+ # ======
+ #
+ require_relative 'models'
+
+ PARTICIPANT_ATTRIBUTES = {}
+ PARTICIPANT_ATTRIBUTES[:registration] =
+ [ :first_name, :last_name, :email,
+ :affiliation, :academic_position,
+ :country, :city, :post_code, :street_address, :phone,
+ :i_m_t_member, :g_d_r_member,
+ :invitation_needed, :visa_needed,
+ :arrival_date, :departure_date,
+ :funding_requests, :special_requests,
+ :talk_proposal_attributes ]
+ PARTICIPANT_ATTRIBUTES[:show] = PARTICIPANT_ATTRIBUTES[:index] =
+ [ :first_name, :last_name, :email, :affiliation,
+ :academic_position,
+ :country, :city, :post_code, :street_address, :phone,
+ :i_m_t_member, :g_d_r_member,
+ :invitation_needed, :visa_needed,
+ :arrival_date, :departure_date,
+ :funding_requests, :special_requests,
+ :approved, :committee_comments ]
+
+ TALK_ATTRIBUTES = {}
+ TALK_ATTRIBUTES[:show] = TALK_ATTRIBUTES[:index] =
+ [ :translated_type_name, :speaker_name, :title, :abstract,
+ :date, :time, :room_or_auditorium ]
+
+ HOTEL_ATTRIBUTES = {}
+ HOTEL_ATTRIBUTES[:show] = HOTEL_ATTRIBUTES[:index] =
+ [:name, :address, :phone, :web_site]
+
+ # Handlers
+ # ========
+ #
+ PUBLIC_PAGES = [ :index,
+ :program,
+ :scientific_committee,
+ :organising_committee,
+ :directions_to_get_here,
+ :funding,
+ :contacts,
+ :accommodation,
+ :participants,
+ :registration,
+ :useful_links ]
+
+ STATIC_PUBLIC_PAGES = Set[ :index,
+ :program,
+ :scientific_committee,
+ :organising_committee,
+ :directions_to_get_here,
+ :funding,
+ :contacts,
+ :accommodation,
+ :useful_links ]
+
+ ORGANISER_CONNEXION_PAGES = [ :'org/participants/to_approve',
+ :'org/participants',
+ :'org/talks',
+ :'org/hotels' ]
+
+ LOCALE_URL_FRAGMENTS = {}.tap { |h| LOCALES.each { |l| h[l] = ["#{ l }/"] } }
+ LOCALE_URL_FRAGMENTS[DEFAULT_LOCALE] << ''
+
+ # LOCALE_URL_FRAGMENT_MAP = { 'fr' => :fr, 'en' => :en, '' => :fr } # this is not used yet
+
+ DEFAULT_PAGE = PUBLIC_PAGES[0]
+ PAGE_URL_FRAGMENTS = {}.tap { |h| PUBLIC_PAGES.each { |p| h[p] = [p.to_s] } }
+ PAGE_URL_FRAGMENTS[DEFAULT_PAGE] << ''
+
+ # Cache control
+ before do
+ cache_control :public, :must_revalidate, :max_age => 60
+ end
+
+
+ # Handle unmatched requests
+ # -------------------------
+
+ not_found do
+ send_file ::File.join(settings.public_folder, '404.html')
+ end
+
+ # GET requests
+ # ------------
+
+ get "#{ REQUEST_BASE_URL }stylesheets/application.css" do
+ content_type :css, :charset => 'utf-8'
+ scss :'/stylesheets/application.css'
+ end
+
+ STATIC_PUBLIC_PAGES.each do |page|
+ page_file = :"/pages/#{ page }.html"
+ LOCALES.each do |locale|
+ LOCALE_URL_FRAGMENTS[locale].each do |l|
+ PAGE_URL_FRAGMENTS[page].each do |p|
+ get "#{ REQUEST_BASE_URL }#{ l }#{ p }" do
+ set_locale(locale)
+ set_page(page)
+ haml page_file, :layout => :layout
+ end
+ end
+ end
+ end
+ end
+
+ LOCALES.each do |locale|
+ LOCALE_URL_FRAGMENTS[locale].each do |l|
+ PAGE_URL_FRAGMENTS[:registration].each do |p|
+ # A page that uses models
+ get "#{ REQUEST_BASE_URL }#{ l }#{ p }" do
+ # @participant = Participant.new :arrival_date => '2013-06-23',
+ # :departure_date => '2013-06-28'
+ @participant = Participant.new
+ render_registration_page(locale)
+ end
+ end
+
+ PAGE_URL_FRAGMENTS[:participants].each do |p|
+ # A page that needs access to the database
+ get "#{ REQUEST_BASE_URL }#{ l }#{ p }" do
+ set_locale(locale)
+ set_page(:participants)
+
+ @participants = Participant.approved.default_order.all
+
+ haml :'/pages/participants.html', :layout => :layout
+ end
+ end
+
+ get "#{ REQUEST_BASE_URL }#{ l }org/login" do
+ set_locale(locale)
+ set_page(:'org/login')
+ haml :'/pages/organiser_connexion/login.html'
+ end
+
+ get "#{ REQUEST_BASE_URL }#{ l }logout" do
+ cache_control :no_cache
+ log_out
+ redirect fixed_url("/#{ locale }/")
+ end
+
+ get "#{ REQUEST_BASE_URL }#{ l }org/" do
+ require_organiser_login!
+ redirect fixed_url("/#{ locale }/org/participants/to_approve")
+ end
+
+ [:'org/participants/to_approve', :'org/participants'].each do |page|
+ get "#{ REQUEST_BASE_URL }#{ l }#{ page }" do
+ require_organiser_login!
+ set_locale(locale)
+ set_page(page)
+ @attributes = PARTICIPANT_ATTRIBUTES[:index]
+ @participants = Participant.scoped
+ if page == :'org/participants/to_approve'
+ @participants = @participants.not_approved
+ end
+ @participants = @participants.default_order.all
+ haml :'/pages/organiser_connexion/participants.html'
+ end
+ end
+
+ get "#{ REQUEST_BASE_URL }#{ l }org/talks" do
+ require_organiser_login!
+ set_locale(locale)
+ set_page(:'org/talks')
+ @attributes = TALK_ATTRIBUTES[:index]
+ @talks = Talk.default_order.all
+ haml :'/pages/organiser_connexion/talks.html'
+ end
+
+ get "#{ REQUEST_BASE_URL }#{ l }org/hotels" do
+ require_organiser_login!
+ set_locale(locale)
+ set_page(:'org/hotels')
+ @attributes = HOTEL_ATTRIBUTES[:index]
+ @hotels = Hotel.default_order.all
+ haml :'/pages/organiser_connexion/hotels.html'
+ end
+
+ [:'org/participants/to_approve', :'org/participants'].each do |page|
+ get "#{ REQUEST_BASE_URL }#{ l }#{ page }/edit/:id" do |id|
+ require_main_organiser_login!
+ set_locale(locale)
+ set_page(page)
+ @attributes = PARTICIPANT_ATTRIBUTES[:index]
+ @participants = Participant.scoped
+ if page == :'org/participants/to_approve'
+ @participants = @participants.not_approved
+ end
+ @participants = @participants.default_order.all
+ @form_participant_id = id.to_i
+ render_edit_participants
+ end
+ end
+
+ get "#{ REQUEST_BASE_URL }#{ l }org/talks/edit/:id" do |id|
+ require_main_organiser_login!
+ set_locale(locale)
+ set_page(:'org/talks')
+ @attributes = TALK_ATTRIBUTES[:index]
+ @talks = Talk.default_order.all
+ @form_talk_id = id.to_i
+ render_edit_talks
+ end
+
+ get "#{ REQUEST_BASE_URL }#{ l }org/hotels/edit/:id" do |id|
+ require_main_organiser_login!
+ set_locale(locale)
+ set_page(:'org/hotels')
+ @attributes = HOTEL_ATTRIBUTES[:index]
+ @hotels = Hotel.default_order.all
+ @form_hotel_id = id.to_i
+ render_edit_hotels
+ end
+
+ [:'org/participants/to_approve', :'org/participants'].each do |page|
+ get "#{ REQUEST_BASE_URL }#{ l }#{ page }/delete/:id" do |id|
+ require_main_organiser_login!
+ set_locale(locale)
+ set_page(page)
+ @participant = Participant.find(id)
+ haml :'/pages/organiser_connexion/delete_participant.html'
+ end
+ end
+
+ get "#{ REQUEST_BASE_URL }#{ l }org/talks/delete/:id" do |id|
+ require_main_organiser_login!
+ set_locale(locale)
+ set_page(:'org/talks')
+ @talk = Talk.find(id)
+ haml :'/pages/organiser_connexion/delete_talk.html'
+ end
+
+ get "#{ REQUEST_BASE_URL }#{ l }org/hotels/delete/:id" do |id|
+ require_main_organiser_login!
+ set_locale(locale)
+ set_page(:'org/hotels')
+ @hotel = Hotel.find(id)
+ haml :'/pages/organiser_connexion/delete_hotel.html'
+ end
+ end
+ end
+
+ get "#{ REQUEST_BASE_URL }login" do
+ redirect fixed_url('/org/login')
+ end
+
+ get "#{ REQUEST_BASE_URL }logout" do
+ cache_control :no_cache
+ log_out
+ redirect fixed_url('/')
+ end
+
+ # POST requests
+ # -------------
+
+ LOCALES.each do |locale|
+ LOCALE_URL_FRAGMENTS[locale].each do |l|
+ PAGE_URL_FRAGMENTS[:registration].each do |p|
+ post "#{ REQUEST_BASE_URL }#{ l }#{ p }" do
+ set_locale(locale)
+
+ # Filter attributes before mass assignement
+ participant_attributes = {}.tap do |h|
+ original_hash = params[:participant]
+ [ :first_name, :last_name, :email,
+ :affiliation, :academic_position,
+ :country, :city, :post_code, :street_address, :phone,
+ :i_m_t_member, :g_d_r_member,
+ :invitation_needed, :visa_needed,
+ :arrival_date, :departure_date,
+ :funding_requests, :special_requests,
+ :talk_proposal_attributes
+ ].each do |attr|
+ value = original_hash[attr.to_s]
+ h[attr] = value unless value.empty?
+ end
+ end
+ talk_proposal_attributes = {}.tap do |h|
+ original_hash = participant_attributes[:talk_proposal_attributes]
+ [:title, :abstract].each do |attr|
+ value = original_hash[attr.to_s]
+ h[attr] = value unless value.empty?
+ end
+ end
+ participant_attributes[:talk_proposal_attributes] =
+ talk_proposal_attributes
+ participant_attributes[:approved] = false
+ @participant = Participant.new(participant_attributes)
+ @participant.generate_pin
+
+ if @participant.save
+ # Send a notification to the organisers
+ email_subject =
+ "CTT 2013: #{ @participant.full_name_with_affiliation }"\
+ " has registered"
+ email_html_body =
+ haml(:'/email/registration_notification.html', :layout => false)
+ email_contents = { :subject => email_subject,
+ :body => @participant.to_yaml,
+ :html_body => email_html_body }
+
+ email_attributes = EMAIL_TO_ORGANISERS_BASIC_ATTRIBUTES.dup
+ email_attributes.merge!(email_contents)
+ Pony.mail email_attributes
+
+ # Send a confirmation to the participant
+ email_body =
+ ::File.read(
+ ::File.join(
+ settings.views,
+ "text/#{ locale }/registration_confirmation.md"),
+ :encoding => 'utf-8:utf-8')
+ email_html_body =
+ haml(:'/email/registration_confirmation.html', :layout => false)
+ email_contents = {
+ :subject => "CTT 2013 registration confirmation",
+ :body => email_body,
+ :html_body => email_html_body }
+
+ email_attributes = EMAIL_TO_PARTICIPANT_BASIC_ATTRIBUTES.dup
+ email_attributes.merge!(email_contents)
+ email_attributes[:to] = @participant.email
+
+ # XXX: for testing only
+ if development?
+ email_attributes[:to] = "#{ ENV['USER'] }@localhost"
+ end
+
+ Pony.mail email_attributes
+
+ # XXX: Registration is not ready to use in production
+ if self.class.production?
+ flash[:notice] =
+ "The registration is not open yet, please try again when the site is ready to use."
+ else
+ flash[:success] = t('flash.resources.participants.create.success')
+ end
+ redirect fixed_url("/#{ locale }/")
+ else
+ flash.now[:error] = t('flash.resources.participants.create.failure')
+ render_registration_page(locale)
+ end
+ end
+ end
+
+ post "#{ REQUEST_BASE_URL }#{ l }org/login" do
+ user = User.find_by_username(params[:username])
+ if user && user.accept_password?(params[:password])
+ log_in(user)
+ redirect fixed_url("/#{ locale }/org/")
+ else
+ flash[:error] = t('flash.sessions.log_in.failure')
+ redirect fixed_url("/#{ locale }/org/login")
+ end
+ end
+ end
+ end
+
+ # PUT requests
+ # ------------
+
+ LOCALES.each do |locale|
+ LOCALE_URL_FRAGMENTS[locale].each do |l|
+
+ [:'org/participants/to_approve', :'org/participants'].each do |page|
+ put "#{ REQUEST_BASE_URL }#{ l }#{ page }/:id" do |id|
+ require_organiser_login!
+ @participant = Participant.find(id)
+ case params[:button]
+ when 'approve'
+ @participant.approved = true
+ when 'disapprove'
+ @participant.approved = false
+ when 'update'
+ require_main_organiser_login!
+ participant_attributes = params[:participant]
+ participant_attributes.each_pair { |k, v|
+ participant_attributes[k] = nil if v.empty?
+ }
+ participant_attributes[:talk_proposal_attributes].tap { |h|
+ h.delete_if { |_, v| v.empty? }
+ h[:_destroy] = true if h.empty?
+ }
+ @participant.update_attributes(participant_attributes)
+ end
+ @participant.save!
+
+ if page == :'org/participants/to_approve'
+ redirect fixed_url("/#{ locale }/org/participants/to_approve#participant_#{ @participant.id }")
+ else
+ redirect fixed_url("/#{ locale }/org/participants#participant_#{ @participant.id }")
+ end
+ end
+ end
+
+ put "#{ REQUEST_BASE_URL }#{ l }org/talk_proposals/:id" do |id|
+ require_main_organiser_login!
+ @talk_proposal = TalkProposal.find(id)
+ case params[:button]
+ when 'accept'
+ @talk_proposal.accept
+ when 'update'
+ talk_proposal_attributes = params[:talk_proposal]
+ talk_proposal_attributes.each_paire { |k, v|
+ talk_proposal_attributes[k] = nil if v.empty?
+ }
+ @talk_proposal.update_attributes(talk_proposal_attributes)
+ end
+ @talk_proposal.save!
+ redirect fixed_url("/#{ locale }/org/participants#participant_#{ @talk_proposal.participant_id }")
+ end
+
+ put "#{ REQUEST_BASE_URL }#{ l }org/talks/:id" do |id|
+ require_main_organiser_login!
+ @talk = Talk.find(id)
+ talk_attributes = params[:talk]
+ talk_attributes.each_pair { |k, v|
+ talk_attributes[k] = nil if v.empty?
+ }
+ @talk.update_attributes(talk_attributes)
+ @talk.save!
+
+ redirect fixed_url("/#{ locale }/org/talks#talk_#{ @talk.id }")
+ end
+
+ put "#{ REQUEST_BASE_URL }#{ l }org/hotels/:id" do |id|
+ require_main_organiser_login!
+ @hotel = Hotel.find(id)
+ hotel_attributes = params[:hotel]
+ hotel_attributes.each_pair { |k, v|
+ hotel_attributes[k] = nil if v.empty?
+ }
+ @hotel.update_attributes(hotel_attributes)
+ @hotel.save!
+
+ redirect fixed_url("/#{ locale }/org/hotels#hotel_#{ @hotel.id }")
+ end
+ end
+ end
+
+ # DELETE requests
+ # ------------
+
+ LOCALES.each do |locale|
+ LOCALE_URL_FRAGMENTS[locale].each do |l|
+ [:'org/participants/to_approve', :'org/participants'].each do |page|
+ delete "#{ REQUEST_BASE_URL }#{ l }#{ page }/:id" do |id|
+ require_main_organiser_login!
+ Participant.find(id).destroy
+ redirect fixed_url("/#{ locale }/#{ page }")
+ end
+ end
+
+ delete "#{ REQUEST_BASE_URL }#{ l }org/talks/:id" do |id|
+ require_main_organiser_login!
+ Talk.find(id).destroy
+ redirect fixed_url("/#{ locale }/org/talks")
+ end
+
+ delete "#{ REQUEST_BASE_URL }#{ l }org/hotels/:id" do |id|
+ require_main_organiser_login!
+ Hotel.find(id).destroy
+ redirect fixed_url("/#{ locale }/org/hotels")
+ end
+ end
+ end
+
+ # View helpers
+ # ============
+ #
+ require_relative 'helpers'
+
+ # Private methods
+ # ===============
+ #
+ private
+
+ def set_locale(locale)
+ I18n.locale = @locale = locale
+ @other_locales = LOCALES.reject { |l| l == @locale }
+ end
+
+ def set_page(page)
+ @page = page
+ @base_title = t('base_page_title')
+ @title = "#{ @base_title } | #{ t(@page, :scope => 'page_titles') }"
+ end
+
+ def locale_from_user_input(suggested_locale)
+ suggested_locale = suggested_locale.to_s.downcase
+ LOCALES.find { |l| l.to_s == suggested_locale } || DEFAULT_LOCALE
+ end
+
+ def page_from_user_input(suggested_page)
+ suggested_page = suggested_page.to_s.downcase
+ PUBLIC_PAGES.find { |p| p.to_s == suggested_page } || DEFAULT_PAGE
+ end
+
+ def render_registration_page(locale)
+ set_locale(locale)
+ set_page(:registration)
+
+ @field_labels = {}
+
+ [ :first_name, :last_name, :email, :affiliation, :academic_position,
+ :country, :city, :post_code, :street_address, :phone,
+ :invitation_needed, :visa_needed, :arrival_date, :departure_date,
+ :funding_requests, :special_requests
+ ].each do |attr|
+ @field_labels[attr] =
+ t(attr, :scope => 'pages.registration.form.field_labels')
+ end
+
+ name = t('names.i_m_t')
+ @field_labels[:i_m_t_member] =
+ t('pages.registration.form.field_labels.i_m_t_member',
+ :link_to_i_m_t =>
+ "<a href='http://www.math.univ-toulouse.fr/' target='_blank'>#{ name }</a>")
+
+ name = t('names.g_d_r_tresses')
+ @field_labels[:g_d_r_member] =
+ t('pages.registration.form.field_labels.g_d_r_member',
+ :link_to_g_d_r =>
+ "<a href='http://tresses.math.cnrs.fr' target='_blank'>#{ name }</a>")
+
+ haml :'/pages/registration.html', :layout => :layout
+ end
+
+ def render_edit_participants
+ @field_labels = Hash.new do |h, k|
+ h[k] = capitalize_first_letter_of(Participant.human_attribute_name(k))
+ end
+ haml :'/pages/organiser_connexion/participants.html'
+ end
+
+ def render_edit_talks
+ @field_labels = Hash.new do |h, k|
+ h[k] = capitalize_first_letter_of(Talk.human_attribute_name(k))
+ end
+ haml :'/pages/organiser_connexion/talks.html'
+ end
+
+ def render_edit_hotels
+ @field_labels = Hash.new do |h, k|
+ h[k] = capitalize_first_letter_of(Hotel.human_attribute_name(k))
+ end
+ haml :'/pages/organiser_connexion/hotels.html'
+ end
+
+ def log_in(user)
+ session[:user_id] = user.id
+ end
+
+ def log_out
+ session.clear
+ end
+
+ def current_user
+ User.find(session[:user_id].to_i)
+ end
+
+ def organiser_logged_in?
+ (user = current_user) &&
+ Set['organiser', 'main_organiser'].include?(user.role)
+ end
+
+ def main_organiser_logged_in?
+ (user = current_user) && user.role == 'main_organiser'
+ end
+
+ def require_organiser_login!
+ unless organiser_logged_in?
+ # halt [ 401, 'Not Authorized' ]
+ flash[:error] = t('flash.filters.require_organiser_login')
+ redirect fixed_url('/org/login')
+ end
+ end
+
+ def require_main_organiser_login!
+ unless main_organiser_logged_in?
+ # halt [ 401, 'Not Authorized' ]
+ flash[:error] = t('flash.filters.require_main_organiser_login')
+ redirect fixed_url('/org/login')
+ end
+ end
+
+end
+
+if __FILE__ == $0
+ CTT2013.connect_database
+ CTT2013.run!
+end
12 config.ru
@@ -0,0 +1,12 @@
+# encoding: UTF-8 (magic comment)
+
+# This file is used for Phusion Passenger, or if deploying to heroku.com
+
+# ENV['RACK_ENV'] = 'production'
+
+require 'rubygems'
+require 'sinatra'
+require './application.rb'
+
+CTT2013.connect_database
+run CTT2013
25 config/database.yml
@@ -0,0 +1,25 @@
+# SQLite version 3.x
+# gem install sqlite3
+#
+# Ensure the SQLite 3 gem is defined in your Gemfile
+# gem 'sqlite3'
+development:
+ adapter: sqlite3
+ database: db/development_db.sqlite3
+ pool: 5
+ timeout: 5000
+
+# Warning: The database defined as "test" may be erased and
+# re-generated from the development database when running rake tasks.
+# Not to set this db to the same as development or production.
+test:
+ adapter: sqlite3
+ database: db/test_db.sqlite3
+ pool: 5
+ timeout: 5000
+
+production:
+ adapter: sqlite3
+ database: db/application_db.sqlite3
+ pool: 5
+ timeout: 5000
57 db/migrate/01_create_participants.rb
@@ -0,0 +1,57 @@
+class CreateParticipants < ActiveRecord::Migration
+ def up
+ create_table 'participants' do |t|
+ t.string 'last_name', :limit => 32, :null => false
+ t.string 'first_name', :limit => 32, :null => false
+ t.string 'name_title', :limit => 16
+ t.string 'email', :limit => 128
+ t.string 'affiliation', :limit => 128
+ t.string 'academic_position', :limit => 32
+ t.string 'country', :limit => 64
+ t.string 'city', :limit => 64
+ t.string 'post_code', :limit => 16
+ t.string 'street_address', :limit => 128
+ t.string 'phone', :limit => 32
+
+ t.string 'gender', :limit => 8
+
+ t.boolean 'approved', :default => false
+
+ t.boolean 'plenary_speaker', :default => false
+ t.boolean 'invited_speaker', :default => false
+ t.boolean 'speaker', :default => false
+ t.boolean 'student', :default => false
+
+ t.boolean 'i_m_t_member', :default => false
+ t.boolean 'g_d_r_member', :default => false
+
+ t.boolean 'visa_needed', :default => false
+ t.boolean 'invitation_needed', :default => false
+
+ t.date 'arrival_date'
+ t.date 'departure_date'
+
+ t.decimal 'registration_fee_payed', :scale => 2, :precision => 5
+
+ t.string 'office_at_i_m_t', :limit => 16
+
+ t.string 'funding_requests'
+ t.string 'special_requests'
+
+ t.text 'committee_comments', :limit => 1024
+
+ t.string 'pin_code_hash', :limit => 64
+
+ t.timestamps
+ end
+
+ add_index 'participants', ['last_name', 'first_name']
+ add_index 'participants', 'approved'
+ add_index 'participants', 'visa_needed'
+ add_index 'participants', 'invitation_needed'
+ end
+
+ def down
+ drop_table 'participants'
+ end
+end
27 db/migrate/02_create_talks.rb
@@ -0,0 +1,27 @@
+class CreateTalks < ActiveRecord::Migration
+ def up
+ create_table 'talks' do |t|
+ t.string 'type'
+ t.integer 'duration_minutes'
+
+ t.integer 'participant_id'
+
+ t.string 'title', :null => false
+ t.text 'abstract'
+ t.string 'joint_with'
+ t.date 'date'
+ t.string 'time'
+
+ t.string 'room_or_auditorium'
+
+ t.timestamps
+ end
+
+ add_index 'talks', 'participant_id'
+ add_index 'talks', ['title', 'participant_id']
+ end
+
+ def down
+ drop_table 'talks'
+ end
+end
21 db/migrate/03_create_talk_proposals.rb
@@ -0,0 +1,21 @@
+class CreateTalkProposals < ActiveRecord::Migration
+ def up
+ create_table 'talk_proposals' do |t|
+ t.integer 'participant_id', :null => false
+ t.integer 'talk_id'
+ t.integer 'duration_minutes'
+ t.string 'type'
+ t.string 'title'
+ t.text 'abstract'
+
+ t.timestamps
+ end
+
+ add_index 'talk_proposals', 'participant_id', :unique => true
+ add_index 'talk_proposals', 'talk_id', :unique => true
+ end
+
+ def down
+ drop_table 'talk_proposals'
+ end
+end
16 db/migrate/04_create_hotels.rb
@@ -0,0 +1,16 @@
+class CreateHotels < ActiveRecord::Migration
+ def up
+ create_table 'hotels' do |t|
+ t.string 'name', :null => false
+ t.string 'address'
+ t.string 'phone'
+ t.string 'web_site'
+
+ t.timestamps
+ end
+ end
+
+ def down
+ drop_table 'hotels'
+ end
+end
20 db/migrate/05_create_accommodations.rb
@@ -0,0 +1,20 @@
+class CreateAccommodations < ActiveRecord::Migration
+ def up
+ create_table 'accommodations' do |t|
+ t.integer 'participant_id', :null => false
+ t.integer 'hotel_id', :null => false
+
+ t.date 'arrival_date'
+ t.date 'departure_date'
+
+ t.timestamps
+ end
+
+ add_index 'accommodations', 'participant_id'
+ add_index 'accommodations', 'hotel_id'
+ end
+
+ def down
+ drop_table 'accommodations'
+ end
+end
16 db/migrate/06_create_conference_dinner_reservations.rb
@@ -0,0 +1,16 @@
+class CreateConferenceDinnerReservations < ActiveRecord::Migration
+ def up
+ create_table 'conference_dinner_reservations' do |t|
+ t.integer 'participant_id', :null => false
+ t.decimal 'amount_payed', :scale => 2, :precision => 4
+
+ t.timestamps
+ end
+
+ add_index 'conference_dinner_reservations', 'participant_id'
+ end
+
+ def down
+ drop_table 'conference_dinner_reservations'
+ end
+end
30 helpers.rb
@@ -0,0 +1,30 @@
+# encoding: UTF-8 (magic comment)
+
+require 'i18n' # Internationalisation
+
+class CTT2013
+ helpers do
+ # Delegate translation helper to I18n
+ def t(*args); I18n.t(*args) end
+
+ # Delegate format localisation helper to I18n
+ def l(*args); I18n.l(*args) end
+
+ def text_from_boolean(bool, options = {})
+ bool ? "#{ t(:yes, options) }" : t(:no, options)
+ end
+
+ def capitalize_first_letter_of(str)
+ unless str.empty?
+ str = ActiveSupport::Multibyte::Chars.new(str)
+ str[0] = str[0].upcase
+ str.to_s
+ end
+ end
+
+ # Patched url helper to work around missing sub URI part
+ def fixed_url(path)
+ url(path, false, false).sub(/\A\//, BASE_URL)
+ end
+ end
+end
205 internationalisation/defaults/en-GB.yml
@@ -0,0 +1,205 @@
+en-GB:
+ date:
+ abbr_day_names:
+ - Sun
+ - Mon
+ - Tue
+ - Wed
+ - Thu
+ - Fri
+ - Sat
+ abbr_month_names:
+ -
+ - Jan
+ - Feb
+ - Mar
+ - Apr
+ - May
+ - Jun
+ - Jul
+ - Aug
+ - Sep
+ - Oct
+ - Nov
+ - Dec
+ day_names:
+ - Sunday
+ - Monday
+ - Tuesday
+ - Wednesday
+ - Thursday
+ - Friday
+ - Saturday
+ formats:
+ default: ! '%d-%m-%Y'
+ long: ! '%d %B, %Y'
+ short: ! '%d %b'
+ month_names:
+ -
+ - January
+ - February
+ - March
+ - April
+ - May
+ - June
+ - July
+ - August
+ - September
+ - October
+ - November
+ - December
+ order:
+ - :day
+ - :month
+ - :year
+ datetime:
+ distance_in_words:
+ about_x_hours:
+ one: about 1 hour
+ other: about %{count} hours
+ about_x_months:
+ one: about 1 month
+ other: about %{count} months
+ about_x_years:
+ one: about 1 year
+ other: about %{count} years
+ almost_x_years:
+ one: almost 1 year
+ other: almost %{count} years
+ half_a_minute: half a minute
+ less_than_x_minutes:
+ one: less than a minute
+ other: less than %{count} minutes
+ less_than_x_seconds:
+ one: less than 1 second
+ other: less than %{count} seconds
+ over_x_years:
+ one: over 1 year
+ other: over %{count} years
+ x_days:
+ one: 1 day
+ other: ! '%{count} days'
+ x_minutes:
+ one: 1 minute
+ other: ! '%{count} minutes'
+ x_months:
+ one: 1 month
+ other: ! '%{count} months'
+ x_seconds:
+ one: 1 second
+ other: ! '%{count} seconds'
+ prompts:
+ day: Day
+ hour: Hour
+ minute: Minute
+ month: Month
+ second: Seconds
+ year: Year
+ errors: &errors
+ format: ! '%{attribute} %{message}'
+ messages:
+ accepted: must be accepted
+ blank: can't be blank
+ confirmation: doesn't match confirmation
+ empty: can't be empty
+ equal_to: must be equal to %{count}
+ even: must be even
+ exclusion: is reserved
+ greater_than: must be greater than %{count}
+ greater_than_or_equal_to: must be greater than or equal to %{count}
+ inclusion: is not included in the list
+ invalid: is invalid
+ less_than: must be less than %{count}
+ less_than_or_equal_to: must be less than or equal to %{count}
+ not_a_number: is not a number
+ not_an_integer: must be an integer
+ odd: must be odd
+ record_invalid: ! 'Validation failed: %{errors}'
+ taken: has already been taken
+ too_long:
+ one: is too long (maximum is 1 character)
+ other: is too long (maximum is %{count} characters)
+ too_short:
+ one: is too short (minimum is 1 character)
+ other: is too short (minimum is %{count} characters)
+ wrong_length:
+ one: is the wrong length (should be 1 character)
+ other: is the wrong length (should be %{count} characters)
+ template:
+ body: ! 'There were problems with the following fields:'
+ header:
+ one: 1 error prohibited this %{model} from being saved
+ other: ! '%{count} errors prohibited this %{model} from being saved'
+ helpers:
+ select:
+ prompt: Please select
+ submit:
+ create: Create %{model}
+ submit: Save %{model}
+ update: Update %{model}
+ number:
+ currency:
+ format:
+ delimiter: ! ','
+ format: ! '%u%n'
+ precision: 2
+ separator: .
+ significant: false
+ strip_insignificant_zeros: false
+ unit: £
+ format:
+ delimiter: ! ','
+ precision: 3
+ separator: .
+ significant: false
+ strip_insignificant_zeros: false
+ human:
+ decimal_units:
+ format: ! '%n %u'
+ units:
+ billion: Billion
+ million: Million
+ quadrillion: Quadrillion
+ thousand: Thousand
+ trillion: Trillion
+ unit: ''
+ format:
+ delimiter: ''
+ precision: 3
+ significant: true
+ strip_insignificant_zeros: true
+ storage_units:
+ format: ! '%n %u'
+ units:
+ byte:
+ one: Byte
+ other: Bytes
+ gb: GB
+ kb: KB
+ mb: MB
+ tb: TB
+ percentage:
+ format:
+ delimiter: ''
+ precision:
+ format:
+ delimiter: ''
+ support:
+ array:
+ last_word_connector: ! ', and '
+ two_words_connector: ! ' and '
+ words_connector: ! ', '
+ time:
+ am: am
+ formats:
+ default: ! '%a, %d %b %Y %H:%M:%S %z'
+ long: ! '%d %B, %Y %H:%M'
+ short: ! '%d %b %H:%M'
+ pm: pm
+ # remove these aliases after 'activemodel' and 'activerecord' namespaces are removed from Rails repository
+ activemodel:
+ errors:
+ <<: *errors
+ activerecord:
+ errors:
+ <<: *errors
205 internationalisation/defaults/en-US.yml
@@ -0,0 +1,205 @@
+en-US:
+ date:
+ abbr_day_names:
+ - Sun
+ - Mon
+ - Tue
+ - Wed
+ - Thu
+ - Fri
+ - Sat
+ abbr_month_names:
+ -
+ - Jan
+ - Feb
+ - Mar
+ - Apr
+ - May
+ - Jun
+ - Jul
+ - Aug
+ - Sep
+ - Oct
+ - Nov
+ - Dec
+ day_names:
+ - Sunday
+ - Monday
+ - Tuesday
+ - Wednesday
+ - Thursday
+ - Friday
+ - Saturday
+ formats:
+ default: ! '%Y-%m-%d'
+ long: ! '%B %d, %Y'
+ short: ! '%b %d'
+ month_names:
+ -
+ - January
+ - February
+ - March
+ - April
+ - May
+ - June
+ - July
+ - August
+ - September
+ - October
+ - November
+ - December
+ order:
+ - :year
+ - :month
+ - :day
+ datetime:
+ distance_in_words:
+ about_x_hours:
+ one: about 1 hour
+ other: about %{count} hours
+ about_x_months:
+ one: about 1 month
+ other: about %{count} months
+ about_x_years:
+ one: about 1 year
+ other: about %{count} years
+ almost_x_years:
+ one: almost 1 year
+ other: almost %{count} years
+ half_a_minute: half a minute
+ less_than_x_minutes:
+ one: less than a minute
+ other: less than %{count} minutes
+ less_than_x_seconds:
+ one: less than 1 second
+ other: less than %{count} seconds
+ over_x_years:
+ one: over 1 year
+ other: over %{count} years
+ x_days:
+ one: 1 day
+ other: ! '%{count} days'
+ x_minutes:
+ one: 1 minute
+ other: ! '%{count} minutes'
+ x_months:
+ one: 1 month
+ other: ! '%{count} months'
+ x_seconds:
+ one: 1 second
+ other: ! '%{count} seconds'
+ prompts:
+ day: Day
+ hour: Hour
+ minute: Minute
+ month: Month
+ second: Seconds
+ year: Year
+ errors: &errors
+ format: ! '%{attribute} %{message}'
+ messages:
+ accepted: must be accepted
+ blank: can't be blank
+ confirmation: doesn't match confirmation
+ empty: can't be empty
+ equal_to: must be equal to %{count}
+ even: must be even
+ exclusion: is reserved
+ greater_than: must be greater than %{count}
+ greater_than_or_equal_to: must be greater than or equal to %{count}
+ inclusion: is not included in the list
+ invalid: is invalid
+ less_than: must be less than %{count}
+ less_than_or_equal_to: must be less than or equal to %{count}
+ not_a_number: is not a number
+ not_an_integer: must be an integer
+ odd: must be odd
+ record_invalid: ! 'Validation failed: %{errors}'
+ taken: has already been taken
+ too_long:
+ one: is too long (maximum is 1 character)
+ other: is too long (maximum is %{count} characters)
+ too_short:
+ one: is too short (minimum is 1 character)
+ other: is too short (minimum is %{count} characters)
+ wrong_length:
+ one: is the wrong length (should be 1 character)
+ other: is the wrong length (should be %{count} characters)
+ template:
+ body: ! 'There were problems with the following fields:'
+ header:
+ one: 1 error prohibited this %{model} from being saved
+ other: ! '%{count} errors prohibited this %{model} from being saved'
+ helpers:
+ select:
+ prompt: Please select
+ submit:
+ create: Create %{model}
+ submit: Save %{model}
+ update: Update %{model}
+ number:
+ currency:
+ format:
+ delimiter: ! ','
+ format: ! '%u%n'
+ precision: 2
+ separator: .
+ significant: false
+ strip_insignificant_zeros: false
+ unit: $
+ format:
+ delimiter: ! ','
+ precision: 3
+ separator: .
+ significant: false
+ strip_insignificant_zeros: false
+ human:
+ decimal_units:
+ format: ! '%n %u'
+ units:
+ billion: Billion
+ million: Million
+ quadrillion: Quadrillion
+ thousand: Thousand
+ trillion: Trillion
+ unit: ''
+ format:
+ delimiter: ''
+ precision: 3
+ significant: true
+ strip_insignificant_zeros: true
+ storage_units:
+ format: ! '%n %u'
+ units:
+ byte:
+ one: Byte
+ other: Bytes
+ gb: GB
+ kb: KB
+ mb: MB
+ tb: TB
+ percentage:
+ format:
+ delimiter: ''
+ precision:
+ format:
+ delimiter: ''
+ support:
+ array:
+ last_word_connector: ! ', and '
+ two_words_connector: ! ' and '
+ words_connector: ! ', '
+ time:
+ am: am
+ formats:
+ default: ! '%a, %d %b %Y %H:%M:%S %z'
+ long: ! '%B %d, %Y %H:%M'
+ short: ! '%d %b %H:%M'
+ pm: pm
+ # remove these aliases after 'activemodel' and 'activerecord' namespaces are removed from Rails repository
+ activemodel:
+ errors:
+ <<: *errors
+ activerecord:
+ errors:
+ <<: *errors
205 internationalisation/defaults/en.yml
@@ -0,0 +1,205 @@
+en:
+ date:
+ abbr_day_names:
+ - Sun
+ - Mon
+ - Tue
+ - Wed
+ - Thu
+ - Fri
+ - Sat
+ abbr_month_names:
+ - ~
+ - Jan
+ - Feb
+ - Mar
+ - Apr
+ - May
+ - Jun
+ - Jul
+ - Aug
+ - Sep
+ - Oct
+ - Nov
+ - Dec
+ day_names:
+ - Sunday
+ - Monday
+ - Tuesday
+ - Wednesday
+ - Thursday
+ - Friday
+ - Saturday
+ formats:
+ default: ! '%d-%m-%Y'
+ long: ! '%d %B, %Y'
+ short: ! '%d %b'
+ month_names:
+ - ~
+ - January
+ - February
+ - March
+ - April
+ - May
+ - June
+ - July
+ - August
+ - September
+ - October
+ - November
+ - December
+ order:
+ - :day
+ - :month
+ - :year
+ datetime:
+ distance_in_words:
+ about_x_hours:
+ one: about 1 hour
+ other: about %{count} hours
+ about_x_months:
+ one: about 1 month
+ other: about %{count} months
+ about_x_years:
+ one: about 1 year
+ other: about %{count} years
+ almost_x_years:
+ one: almost 1 year
+ other: almost %{count} years
+ half_a_minute: half a minute
+ less_than_x_minutes:
+ one: less than a minute
+ other: less than %{count} minutes
+ less_than_x_seconds:
+ one: less than 1 second
+ other: less than %{count} seconds
+ over_x_years:
+ one: over 1 year
+ other: over %{count} years
+ x_days:
+ one: 1 day
+ other: ! '%{count} days'
+ x_minutes:
+ one: 1 minute
+ other: ! '%{count} minutes'
+ x_months:
+ one: 1 month
+ other: ! '%{count} months'
+ x_seconds:
+ one: 1 second
+ other: ! '%{count} seconds'
+ prompts:
+ day: Day
+ hour: Hour
+ minute: Minute
+ month: Month
+ second: Seconds
+ year: Year
+ errors: &errors
+ format: ! '%{attribute} %{message}'
+ messages:
+ accepted: must be accepted
+ blank: can't be blank
+ confirmation: doesn't match confirmation
+ empty: can't be empty
+ equal_to: must be equal to %{count}
+ even: must be even
+ exclusion: is reserved
+ greater_than: must be greater than %{count}
+ greater_than_or_equal_to: must be greater than or equal to %{count}
+ inclusion: is not included in the list
+ invalid: is invalid
+ less_than: must be less than %{count}
+ less_than_or_equal_to: must be less than or equal to %{count}
+ not_a_number: is not a number
+ not_an_integer: must be an integer
+ odd: must be odd
+ record_invalid: ! 'Validation failed: %{errors}'
+ taken: has already been taken
+ too_long:
+ one: is too long (maximum is 1 character)
+ other: is too long (maximum is %{count} characters)
+ too_short:
+ one: is too short (minimum is 1 character)
+ other: is too short (minimum is %{count} characters)
+ wrong_length:
+ one: is the wrong length (should be 1 character)
+ other: is the wrong length (should be %{count} characters)
+ template:
+ body: ! 'There were problems with the following fields:'
+ header:
+ one: 1 error prohibited this %{model} from being saved
+ other: ! '%{count} errors prohibited this %{model} from being saved'
+ helpers:
+ select:
+ prompt: Please select
+ submit:
+ create: Create %{model}
+ submit: Save %{model}
+ update: Update %{model}
+ number:
+ currency:
+ format:
+ delimiter: ! ','
+ format: ! '%u%n'
+ precision: 2
+ separator: .
+ significant: false
+ strip_insignificant_zeros: false
+ unit: £
+ format:
+ delimiter: ! ','
+ precision: 3
+ separator: .
+ significant: false
+ strip_insignificant_zeros: false
+ human:
+ decimal_units:
+ format: ! '%n %u'
+ units:
+ billion: Billion
+ million: Million
+ quadrillion: Quadrillion
+ thousand: Thousand
+ trillion: Trillion
+ unit: ''
+ format:
+ delimiter: ''
+ precision: 3
+ significant: true
+ strip_insignificant_zeros: true
+ storage_units:
+ format: ! '%n %u'
+ units:
+ byte:
+ one: Byte
+ other: Bytes
+ gb: GB
+ kb: KB
+ mb: MB
+ tb: TB
+ percentage:
+ format:
+ delimiter: ''
+ precision:
+ format:
+ delimiter: ''
+ support:
+ array:
+ last_word_connector: ! ', and '
+ two_words_connector: ! ' and '
+ words_connector: ! ', '
+ time:
+ am: am
+ formats:
+ default: ! '%a, %d %b %Y %H:%M:%S %z'
+ long: ! '%d %B, %Y %H:%M'
+ short: ! '%d %b %H:%M'
+ pm: pm
+ # remove these aliases after 'activemodel' and 'activerecord' namespaces are removed from Rails repository
+ activemodel:
+ errors:
+ <<: *errors
+ activerecord:
+ errors:
+ <<: *errors
222 internationalisation/defaults/fr.yml
@@ -0,0 +1,222 @@
+# French translations for Ruby on Rails
+# by Christian Lescuyer (christian@flyingcoders.com)
+# contributors:
+# - Sebastien Grosjean - ZenCocoon.com
+# - Bruno Michel - http://github.com/nono
+# - Tsutomu Kuroda - http://github.com/kuroda (t-kuroda@oiax.jp)
+# Emended by Benjamin des Gachons and Patrick Chew·: <http://www.fitima.org/docs/fiche.pdf>
+
+fr:
+ date:
+ formats:
+ default: "%d/%m/%Y"
+ short: "%e %b"
+ long: "%e %B %Y"
+ day_names:
+ - dimanche
+ - lundi
+ - mardi
+ - mercredi
+ - jeudi
+ - vendredi
+ - samedi
+ abbr_day_names:
+ - dim
+ - lun
+ - mar
+ - mer
+ - jeu
+ - ven
+ - sam
+ month_names:
+ - ~
+ - janvier
+ - février
+ - mars
+ - avril
+ - mai
+ - juin
+ - juillet
+ - août
+ - septembre
+ - octobre
+ - novembre
+ - décembre
+ abbr_month_names:
+ - ~
+ - jan.
+ - fév.
+ - mar.
+ - avr.
+ - mai
+ - juin
+ - juil.
+ - août
+ - sept.
+ - oct.
+ - nov.
+ - déc.
+ order:
+ - :day
+ - :month
+ - :year
+
+ time:
+ formats:
+ default: "%d %B %Y %H:%M:%S"
+ short: "%d %b %H:%M"
+ long: "%A %d %B %Y %H:%M"
+ am: 'am'
+ pm: 'pm'
+
+ datetime:
+ distance_in_words:
+ half_a_minute: "une demi-minute"
+ less_than_x_seconds:
+ zero: "moins d'une seconde"
+ one: "moins d'une seconde"
+ other: "moins de %{count} secondes"
+ x_seconds:
+ one: "1 seconde"
+ other: "%{count} secondes"
+ less_than_x_minutes:
+ zero: "moins d'une minute"
+ one: "moins d'une minute"
+ other: "moins de %{count} minutes"
+ x_minutes:
+ one: "1 minute"
+ other: "%{count} minutes"
+ about_x_hours:
+ one: "environ une heure"
+ other: "environ %{count} heures"
+ x_days:
+ one: "1 jour"
+ other: "%{count} jours"
+ about_x_months:
+ one: "environ un mois"
+ other: "environ %{count} mois"
+ x_months:
+ one: "1 mois"
+ other: "%{count} mois"
+ about_x_years:
+ one: "environ un an"
+ other: "environ %{count} ans"
+ over_x_years:
+ one: "plus d'un an"
+ other: "plus de %{count} ans"
+ almost_x_years:
+ one: "presqu'un an"
+ other: "presque %{count} ans"
+ prompts:
+ year: "Année"
+ month: "Mois"
+ day: "Jour"
+ hour: "Heure"
+ minute: "Minute"
+ second: "Seconde"
+
+ number:
+ format:
+ separator: ","
+ delimiter: " "
+ precision: 3
+ significant: false
+ strip_insignificant_zeros: false
+ currency:
+ format:
+ format: "%n %u"
+ unit: ""
+ separator: ","
+ delimiter: " "
+ precision: 2
+ significant: false
+ strip_insignificant_zeros: false
+ percentage:
+ format:
+