diff --git a/Gemfile b/Gemfile new file mode 100644 index 00000000..8722ffd8 --- /dev/null +++ b/Gemfile @@ -0,0 +1,50 @@ +source 'https://rubygems.org' + +gem 'rails', '3.2.9' + +# Bundle edge Rails instead: +# gem 'rails', :git => 'git://github.com/rails/rails.git' + +gem 'sqlite3' + + +# Gems used only for assets and not required +# in production environments by default. +group :assets do + gem 'sass-rails', '~> 3.2.3' + gem 'coffee-rails', '~> 3.2.1' + + # See https://github.com/sstephenson/execjs#readme for more supported runtimes + # gem 'therubyracer', :platforms => :ruby + + gem 'uglifier', '>= 1.0.3' +end + +gem 'paperclip', '~> 3.0' +gem 'jquery-rails' +gem 'jquery_datepicker' +gem 'jquery-fileupload-rails' +gem 'devise' +gem 'cancan' +gem "haml" +gem 'bcrypt-ruby', '~> 3.0.0' +gem 'node' +gem 'twitter-bootstrap-rails' +gem 'formtastic-bootstrap' +gem 'cocoon' +gem 'transitions', :require => ["transitions", "active_record/transitions"] +gem 'acts_as_commentable_with_threading' +gem 'prawn' +gem 'prawn_rails' + +# To use Jbuilder templates for JSON +# gem 'jbuilder' + +# Use unicorn as the app server +# gem 'unicorn' + +# Deploy with Capistrano +# gem 'capistrano' + +# To use debugger +# gem 'debugger' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 00000000..087506f4 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,183 @@ +GEM + remote: https://rubygems.org/ + specs: + Ascii85 (1.0.2) + actionmailer (3.2.9) + actionpack (= 3.2.9) + mail (~> 2.4.4) + actionpack (3.2.9) + activemodel (= 3.2.9) + activesupport (= 3.2.9) + builder (~> 3.0.0) + erubis (~> 2.7.0) + journey (~> 1.0.4) + rack (~> 1.4.0) + rack-cache (~> 1.2) + rack-test (~> 0.6.1) + sprockets (~> 2.2.1) + activemodel (3.2.9) + activesupport (= 3.2.9) + builder (~> 3.0.0) + activerecord (3.2.9) + activemodel (= 3.2.9) + activesupport (= 3.2.9) + arel (~> 3.0.2) + tzinfo (~> 0.3.29) + activeresource (3.2.9) + activemodel (= 3.2.9) + activesupport (= 3.2.9) + activesupport (3.2.9) + i18n (~> 0.6) + multi_json (~> 1.0) + acts_as_commentable_with_threading (1.1.2) + activerecord (>= 3.0) + activesupport (~> 3.0) + awesome_nested_set (>= 2.0) + arel (3.0.2) + awesome_nested_set (2.1.5) + activerecord (>= 3.0.0) + bcrypt-ruby (3.0.1) + builder (3.0.4) + cancan (1.6.8) + cocaine (0.4.2) + cocoon (1.1.1) + coffee-rails (3.2.2) + coffee-script (>= 2.2.0) + railties (~> 3.2.0) + coffee-script (2.2.0) + coffee-script-source + execjs + coffee-script-source (1.4.0) + devise (2.1.2) + bcrypt-ruby (~> 3.0) + orm_adapter (~> 0.1) + railties (~> 3.1) + warden (~> 1.2.1) + erubis (2.7.0) + eventmachine (1.0.0) + execjs (1.4.0) + multi_json (~> 1.0) + formtastic (2.2.1) + actionpack (>= 3.0) + formtastic-bootstrap (2.0.0) + formtastic (~> 2.2) + formtastic-bootstrap + haml (3.1.7) + hashery (2.1.0) + hike (1.2.1) + i18n (0.6.1) + journey (1.0.4) + jquery-fileupload-rails (0.4.0) + actionpack (>= 3.1) + railties (>= 3.1) + jquery-rails (2.1.4) + railties (>= 3.0, < 5.0) + thor (>= 0.14, < 2.0) + jquery_datepicker (0.4) + json (1.7.5) + mail (2.4.4) + i18n (>= 0.4.0) + mime-types (~> 1.16) + treetop (~> 1.4.8) + mime-types (1.19) + multi_json (1.5.0) + node (0.0.2) + eventmachine + orm_adapter (0.4.0) + paperclip (3.4.0) + activemodel (>= 3.0.0) + activerecord (>= 3.0.0) + activesupport (>= 3.0.0) + cocaine (~> 0.4.0) + mime-types + pdf-reader (1.2.0) + Ascii85 (~> 1.0.0) + hashery (~> 2.0) + ruby-rc4 + polyglot (0.3.3) + prawn (0.12.0) + pdf-reader (>= 0.9.0) + ttfunk (~> 1.0.2) + prawn_rails (0.0.11) + prawn (>= 0.11.1) + railties (>= 3.0.0) + rack (1.4.1) + rack-cache (1.2) + rack (>= 0.4) + rack-ssl (1.3.2) + rack + rack-test (0.6.2) + rack (>= 1.0) + rails (3.2.9) + actionmailer (= 3.2.9) + actionpack (= 3.2.9) + activerecord (= 3.2.9) + activeresource (= 3.2.9) + activesupport (= 3.2.9) + bundler (~> 1.0) + railties (= 3.2.9) + railties (3.2.9) + actionpack (= 3.2.9) + activesupport (= 3.2.9) + rack-ssl (~> 1.3.2) + rake (>= 0.8.7) + rdoc (~> 3.4) + thor (>= 0.14.6, < 2.0) + rake (10.0.3) + rdoc (3.12) + json (~> 1.4) + ruby-rc4 (0.1.5) + sass (3.2.4) + sass-rails (3.2.5) + railties (~> 3.2.0) + sass (>= 3.1.10) + tilt (~> 1.3) + sprockets (2.2.2) + hike (~> 1.2) + multi_json (~> 1.0) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sqlite3 (1.3.6) + thor (0.16.0) + tilt (1.3.3) + transitions (0.1.4) + treetop (1.4.12) + polyglot + polyglot (>= 0.3.1) + ttfunk (1.0.3) + twitter-bootstrap-rails (2.1.9) + actionpack (>= 3.1) + execjs + railties (>= 3.1) + tzinfo (0.3.35) + uglifier (1.3.0) + execjs (>= 0.3.0) + multi_json (~> 1.0, >= 1.0.2) + warden (1.2.1) + rack (>= 1.0) + +PLATFORMS + ruby + +DEPENDENCIES + acts_as_commentable_with_threading + bcrypt-ruby (~> 3.0.0) + cancan + cocoon + coffee-rails (~> 3.2.1) + devise + formtastic-bootstrap + haml + jquery-fileupload-rails + jquery-rails + jquery_datepicker + node + paperclip (~> 3.0) + prawn + prawn_rails + rails (= 3.2.9) + sass-rails (~> 3.2.3) + sqlite3 + transitions + twitter-bootstrap-rails + uglifier (>= 1.0.3) diff --git a/README.rdoc b/README.rdoc new file mode 100644 index 00000000..7c36f235 --- /dev/null +++ b/README.rdoc @@ -0,0 +1,261 @@ +== Welcome to Rails + +Rails is a web-application framework that includes everything needed to create +database-backed web applications according to the Model-View-Control pattern. + +This pattern splits the view (also called the presentation) into "dumb" +templates that are primarily responsible for inserting pre-built data in between +HTML tags. The model contains the "smart" domain objects (such as Account, +Product, Person, Post) that holds all the business logic and knows how to +persist themselves to a database. The controller handles the incoming requests +(such as Save New Account, Update Product, Show Post) by manipulating the model +and directing data to the view. + +In Rails, the model is handled by what's called an object-relational mapping +layer entitled Active Record. This layer allows you to present the data from +database rows as objects and embellish these data objects with business logic +methods. You can read more about Active Record in +link:files/vendor/rails/activerecord/README.html. + +The controller and view are handled by the Action Pack, which handles both +layers by its two parts: Action View and Action Controller. These two layers +are bundled in a single package due to their heavy interdependence. This is +unlike the relationship between the Active Record and Action Pack that is much +more separate. Each of these packages can be used independently outside of +Rails. You can read more about Action Pack in +link:files/vendor/rails/actionpack/README.html. + + +== Getting Started + +1. At the command prompt, create a new Rails application: + rails new myapp (where myapp is the application name) + +2. Change directory to myapp and start the web server: + cd myapp; rails server (run with --help for options) + +3. Go to http://localhost:3000/ and you'll see: + "Welcome aboard: You're riding Ruby on Rails!" + +4. Follow the guidelines to start developing your application. You can find +the following resources handy: + +* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html +* Ruby on Rails Tutorial Book: http://www.railstutorial.org/ + + +== Debugging Rails + +Sometimes your application goes wrong. Fortunately there are a lot of tools that +will help you debug it and get it back on the rails. + +First area to check is the application log files. Have "tail -f" commands +running on the server.log and development.log. Rails will automatically display +debugging and runtime information to these files. Debugging info will also be +shown in the browser on requests from 127.0.0.1. + +You can also log your own messages directly into the log file from your code +using the Ruby logger class from inside your controllers. Example: + + class WeblogController < ActionController::Base + def destroy + @weblog = Weblog.find(params[:id]) + @weblog.destroy + logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!") + end + end + +The result will be a message in your log file along the lines of: + + Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1! + +More information on how to use the logger is at http://www.ruby-doc.org/core/ + +Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are +several books available online as well: + +* Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe) +* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide) + +These two books will bring you up to speed on the Ruby language and also on +programming in general. + + +== Debugger + +Debugger support is available through the debugger command when you start your +Mongrel or WEBrick server with --debugger. This means that you can break out of +execution at any point in the code, investigate and change the model, and then, +resume execution! You need to install ruby-debug to run the server in debugging +mode. With gems, use sudo gem install ruby-debug. Example: + + class WeblogController < ActionController::Base + def index + @posts = Post.all + debugger + end + end + +So the controller will accept the action, run the first line, then present you +with a IRB prompt in the server window. Here you can do things like: + + >> @posts.inspect + => "[#nil, "body"=>nil, "id"=>"1"}>, + #"Rails", "body"=>"Only ten..", "id"=>"2"}>]" + >> @posts.first.title = "hello from a debugger" + => "hello from a debugger" + +...and even better, you can examine how your runtime objects actually work: + + >> f = @posts.first + => #nil, "body"=>nil, "id"=>"1"}> + >> f. + Display all 152 possibilities? (y or n) + +Finally, when you're ready to resume execution, you can enter "cont". + + +== Console + +The console is a Ruby shell, which allows you to interact with your +application's domain model. Here you'll have all parts of the application +configured, just like it is when the application is running. You can inspect +domain models, change values, and save to the database. Starting the script +without arguments will launch it in the development environment. + +To start the console, run rails console from the application +directory. + +Options: + +* Passing the -s, --sandbox argument will rollback any modifications + made to the database. +* Passing an environment name as an argument will load the corresponding + environment. Example: rails console production. + +To reload your controllers and models after launching the console run +reload! + +More information about irb can be found at: +link:http://www.rubycentral.org/pickaxe/irb.html + + +== dbconsole + +You can go to the command line of your database directly through rails +dbconsole. You would be connected to the database with the credentials +defined in database.yml. Starting the script without arguments will connect you +to the development database. Passing an argument will connect you to a different +database, like rails dbconsole production. Currently works for MySQL, +PostgreSQL and SQLite 3. + +== Description of Contents + +The default directory structure of a generated Ruby on Rails application: + + |-- app + | |-- assets + | |-- images + | |-- javascripts + | `-- stylesheets + | |-- controllers + | |-- helpers + | |-- mailers + | |-- models + | `-- views + | `-- layouts + |-- config + | |-- environments + | |-- initializers + | `-- locales + |-- db + |-- doc + |-- lib + | `-- tasks + |-- log + |-- public + |-- script + |-- test + | |-- fixtures + | |-- functional + | |-- integration + | |-- performance + | `-- unit + |-- tmp + | |-- cache + | |-- pids + | |-- sessions + | `-- sockets + `-- vendor + |-- assets + `-- stylesheets + `-- plugins + +app + Holds all the code that's specific to this particular application. + +app/assets + Contains subdirectories for images, stylesheets, and JavaScript files. + +app/controllers + Holds controllers that should be named like weblogs_controller.rb for + automated URL mapping. All controllers should descend from + ApplicationController which itself descends from ActionController::Base. + +app/models + Holds models that should be named like post.rb. Models descend from + ActiveRecord::Base by default. + +app/views + Holds the template files for the view that should be named like + weblogs/index.html.erb for the WeblogsController#index action. All views use + eRuby syntax by default. + +app/views/layouts + Holds the template files for layouts to be used with views. This models the + common header/footer method of wrapping views. In your views, define a layout + using the layout :default and create a file named default.html.erb. + Inside default.html.erb, call <% yield %> to render the view using this + layout. + +app/helpers + Holds view helpers that should be named like weblogs_helper.rb. These are + generated for you automatically when using generators for controllers. + Helpers can be used to wrap functionality for your views into methods. + +config + Configuration files for the Rails environment, the routing map, the database, + and other dependencies. + +db + Contains the database schema in schema.rb. db/migrate contains all the + sequence of Migrations for your schema. + +doc + This directory is where your application documentation will be stored when + generated using rake doc:app + +lib + Application specific libraries. Basically, any kind of custom code that + doesn't belong under controllers, models, or helpers. This directory is in + the load path. + +public + The directory available for the web server. Also contains the dispatchers and the + default HTML files. This should be set as the DOCUMENT_ROOT of your web + server. + +script + Helper scripts for automation and generation. + +test + Unit and functional tests along with fixtures. When using the rails generate + command, template test files will be generated for you and placed in this + directory. + +vendor + External libraries that the application depends on. Also includes the plugins + subdirectory. If the app has frozen rails, those gems also go here, under + vendor/rails/. This directory is in the load path. diff --git a/Rakefile b/Rakefile new file mode 100644 index 00000000..f29eb6f1 --- /dev/null +++ b/Rakefile @@ -0,0 +1,7 @@ +#!/usr/bin/env rake +# 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__) + +Osem::Application.load_tasks diff --git a/app/assets/images/rails.png b/app/assets/images/rails.png new file mode 100644 index 00000000..d5edc04e Binary files /dev/null and b/app/assets/images/rails.png differ diff --git a/app/assets/images/ui-bg_flat_0_aaaaaa_40x100.png b/app/assets/images/ui-bg_flat_0_aaaaaa_40x100.png new file mode 100644 index 00000000..5b5dab2a Binary files /dev/null and b/app/assets/images/ui-bg_flat_0_aaaaaa_40x100.png differ diff --git a/app/assets/images/ui-bg_flat_55_fbec88_40x100.png b/app/assets/images/ui-bg_flat_55_fbec88_40x100.png new file mode 100644 index 00000000..47acaadd Binary files /dev/null and b/app/assets/images/ui-bg_flat_55_fbec88_40x100.png differ diff --git a/app/assets/images/ui-bg_glass_75_d0e5f5_1x400.png b/app/assets/images/ui-bg_glass_75_d0e5f5_1x400.png new file mode 100644 index 00000000..9fb564f8 Binary files /dev/null and b/app/assets/images/ui-bg_glass_75_d0e5f5_1x400.png differ diff --git a/app/assets/images/ui-bg_glass_85_dfeffc_1x400.png b/app/assets/images/ui-bg_glass_85_dfeffc_1x400.png new file mode 100644 index 00000000..01495152 Binary files /dev/null and b/app/assets/images/ui-bg_glass_85_dfeffc_1x400.png differ diff --git a/app/assets/images/ui-bg_glass_95_fef1ec_1x400.png b/app/assets/images/ui-bg_glass_95_fef1ec_1x400.png new file mode 100644 index 00000000..8f28bc99 Binary files /dev/null and b/app/assets/images/ui-bg_glass_95_fef1ec_1x400.png differ diff --git a/app/assets/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png b/app/assets/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png new file mode 100644 index 00000000..81ecc362 Binary files /dev/null and b/app/assets/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png differ diff --git a/app/assets/images/ui-bg_inset-hard_100_f5f8f9_1x100.png b/app/assets/images/ui-bg_inset-hard_100_f5f8f9_1x100.png new file mode 100644 index 00000000..4f3faf8a Binary files /dev/null and b/app/assets/images/ui-bg_inset-hard_100_f5f8f9_1x100.png differ diff --git a/app/assets/images/ui-bg_inset-hard_100_fcfdfd_1x100.png b/app/assets/images/ui-bg_inset-hard_100_fcfdfd_1x100.png new file mode 100644 index 00000000..38c38335 Binary files /dev/null and b/app/assets/images/ui-bg_inset-hard_100_fcfdfd_1x100.png differ diff --git a/app/assets/images/ui-icons_217bc0_256x240.png b/app/assets/images/ui-icons_217bc0_256x240.png new file mode 100644 index 00000000..6f4bd87c Binary files /dev/null and b/app/assets/images/ui-icons_217bc0_256x240.png differ diff --git a/app/assets/images/ui-icons_2e83ff_256x240.png b/app/assets/images/ui-icons_2e83ff_256x240.png new file mode 100644 index 00000000..09d1cdc8 Binary files /dev/null and b/app/assets/images/ui-icons_2e83ff_256x240.png differ diff --git a/app/assets/images/ui-icons_469bdd_256x240.png b/app/assets/images/ui-icons_469bdd_256x240.png new file mode 100644 index 00000000..bd2cf079 Binary files /dev/null and b/app/assets/images/ui-icons_469bdd_256x240.png differ diff --git a/app/assets/images/ui-icons_6da8d5_256x240.png b/app/assets/images/ui-icons_6da8d5_256x240.png new file mode 100644 index 00000000..9f3eafaa Binary files /dev/null and b/app/assets/images/ui-icons_6da8d5_256x240.png differ diff --git a/app/assets/images/ui-icons_cd0a0a_256x240.png b/app/assets/images/ui-icons_cd0a0a_256x240.png new file mode 100644 index 00000000..2ab019b7 Binary files /dev/null and b/app/assets/images/ui-icons_cd0a0a_256x240.png differ diff --git a/app/assets/images/ui-icons_d8e7f3_256x240.png b/app/assets/images/ui-icons_d8e7f3_256x240.png new file mode 100644 index 00000000..ad2dc6f9 Binary files /dev/null and b/app/assets/images/ui-icons_d8e7f3_256x240.png differ diff --git a/app/assets/images/ui-icons_f9bd01_256x240.png b/app/assets/images/ui-icons_f9bd01_256x240.png new file mode 100644 index 00000000..c7c53cb1 Binary files /dev/null and b/app/assets/images/ui-icons_f9bd01_256x240.png differ diff --git a/app/assets/javascripts/admin/admin.js.coffee b/app/assets/javascripts/admin/admin.js.coffee new file mode 100644 index 00000000..76156794 --- /dev/null +++ b/app/assets/javascripts/admin/admin.js.coffee @@ -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://jashkenas.github.com/coffee-script/ diff --git a/app/assets/javascripts/admin/call_for_papers.js.coffee b/app/assets/javascripts/admin/call_for_papers.js.coffee new file mode 100644 index 00000000..76156794 --- /dev/null +++ b/app/assets/javascripts/admin/call_for_papers.js.coffee @@ -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://jashkenas.github.com/coffee-script/ diff --git a/app/assets/javascripts/admin/conference.js.coffee b/app/assets/javascripts/admin/conference.js.coffee new file mode 100644 index 00000000..76156794 --- /dev/null +++ b/app/assets/javascripts/admin/conference.js.coffee @@ -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://jashkenas.github.com/coffee-script/ diff --git a/app/assets/javascripts/admin/people.js.coffee b/app/assets/javascripts/admin/people.js.coffee new file mode 100644 index 00000000..76156794 --- /dev/null +++ b/app/assets/javascripts/admin/people.js.coffee @@ -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://jashkenas.github.com/coffee-script/ diff --git a/app/assets/javascripts/admin/users.js.coffee b/app/assets/javascripts/admin/users.js.coffee new file mode 100644 index 00000000..76156794 --- /dev/null +++ b/app/assets/javascripts/admin/users.js.coffee @@ -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://jashkenas.github.com/coffee-script/ diff --git a/app/assets/javascripts/admin/venue.js.coffee b/app/assets/javascripts/admin/venue.js.coffee new file mode 100644 index 00000000..76156794 --- /dev/null +++ b/app/assets/javascripts/admin/venue.js.coffee @@ -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://jashkenas.github.com/coffee-script/ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js new file mode 100644 index 00000000..e5ec8a6e --- /dev/null +++ b/app/assets/javascripts/application.js @@ -0,0 +1,74 @@ +// 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 vendor/assets/javascripts of plugins, if any, 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 +// the compiled file. +// +// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD +// GO AFTER THE REQUIRES BELOW. +// +//= require jquery +//= require jquery_ujs +//= require jquery-ui +//= require jquery-fileupload +//= require twitter/bootstrap +//= require cocoon + +$(function() { + + $('.dropdown-toggle').dropdown(); + $("#conference-start-datepicker").datepicker({ + dateFormat: 'yy/mm/dd', + numberOfMonths: 2, + onSelect: function(selected) { + $("#conference-end-datepicker").datepicker("option","minDate", selected) + } + }); + $("#conference-end-datepicker").datepicker({ + dateFormat: 'yy/mm/dd', + numberOfMonths: 2, + onSelect: function(selected) { + $("#conference-start-datepicker").datepicker("option","maxDate", selected) + $("#cfp-hard-datepicker").datepicker("option","minDate", selected) + + } + }); + + $("#cfp-hard-datepicker").datepicker({ + dateFormat: 'yy/mm/dd', + numberOfMonths: 2, + onSelect: function(selected) { + $("#conference-end-datepicker").datepicker("option","maxDate", selected) + $("#conference-start-datepicker").datepicker("option","maxDate", selected) + + } + }); + + $(".comment-reply-link").click(function(){ + $(".comment-reply", $(this).parent()).toggle(); + return false; + }); + + $("#event-comment-link").click(function(){ + $("#comments-div").toggle(); + return false; + }); + + $(".comment-reply").hide(); + $(".user-details-popover").popover(); + $("#comments-div").hide(); +}); + +function word_count(text, divId){ + var r = 0; + var input = text.value.replace(/\s/g,' '); + var word_array = input.split(' '); + for (var i=0; i < word_array.length; i++) { + if (word_array[i].length > 0) r++; + } + + $('#' + divId).text(r); +} \ No newline at end of file diff --git a/app/assets/javascripts/bootstrap.js.coffee b/app/assets/javascripts/bootstrap.js.coffee new file mode 100644 index 00000000..c9404a8e --- /dev/null +++ b/app/assets/javascripts/bootstrap.js.coffee @@ -0,0 +1,4 @@ +jQuery -> + $("a[rel=popover]").popover() + $(".tooltip").tooltip() + $("a[rel=tooltip]").tooltip() \ No newline at end of file diff --git a/app/assets/javascripts/home.js.coffee b/app/assets/javascripts/home.js.coffee new file mode 100644 index 00000000..76156794 --- /dev/null +++ b/app/assets/javascripts/home.js.coffee @@ -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://jashkenas.github.com/coffee-script/ diff --git a/app/assets/stylesheets/admin/admin.css.scss b/app/assets/stylesheets/admin/admin.css.scss new file mode 100644 index 00000000..914a004c --- /dev/null +++ b/app/assets/stylesheets/admin/admin.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the admin/admin controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/admin/call_for_papers.css.scss b/app/assets/stylesheets/admin/call_for_papers.css.scss new file mode 100644 index 00000000..80170c0a --- /dev/null +++ b/app/assets/stylesheets/admin/call_for_papers.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the admin/call_for_papers controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/admin/conference.css.scss b/app/assets/stylesheets/admin/conference.css.scss new file mode 100644 index 00000000..82491508 --- /dev/null +++ b/app/assets/stylesheets/admin/conference.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the admin/conference controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/admin/people.css.scss b/app/assets/stylesheets/admin/people.css.scss new file mode 100644 index 00000000..de8637ff --- /dev/null +++ b/app/assets/stylesheets/admin/people.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the admin/people controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/admin/users.css.scss b/app/assets/stylesheets/admin/users.css.scss new file mode 100644 index 00000000..925e3122 --- /dev/null +++ b/app/assets/stylesheets/admin/users.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the admin/users controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/admin/venue.css.scss b/app/assets/stylesheets/admin/venue.css.scss new file mode 100644 index 00000000..6a29a24d --- /dev/null +++ b/app/assets/stylesheets/admin/venue.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the admin/venue controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css new file mode 100644 index 00000000..95b82e02 --- /dev/null +++ b/app/assets/stylesheets/application.css @@ -0,0 +1,7 @@ +/* + *= require formtastic-bootstrap + *= require bootstrap_and_overrides + *= require osem + *= require jquery-ui-1.9.2.custom + *= require jquery.fileupload-ui +*/ diff --git a/app/assets/stylesheets/bootstrap_and_overrides.css b/app/assets/stylesheets/bootstrap_and_overrides.css new file mode 100644 index 00000000..131fcfd7 --- /dev/null +++ b/app/assets/stylesheets/bootstrap_and_overrides.css @@ -0,0 +1,7 @@ +/* + =require twitter-bootstrap-static/bootstrap + + Use Font Awesome icons (default) + To use Glyphicons sprites instead of Font Awesome, replace with "require twitter-bootstrap-static/sprites" + =require twitter-bootstrap-static/fontawesome + */ \ No newline at end of file diff --git a/app/assets/stylesheets/bootstrap_and_overrides.css.less b/app/assets/stylesheets/bootstrap_and_overrides.css.less new file mode 100644 index 00000000..67299b01 --- /dev/null +++ b/app/assets/stylesheets/bootstrap_and_overrides.css.less @@ -0,0 +1,33 @@ +@import "twitter/bootstrap/bootstrap"; +@import "twitter/bootstrap/responsive"; + +// Set the correct sprite paths +@iconSpritePath: asset-path("twitter/bootstrap/glyphicons-halflings"); +@iconWhiteSpritePath: asset-path("twitter/bootstrap/glyphicons-halflings-white"); + +// Set the Font Awesome (Font Awesome is default. You can disable by commenting below lines) +// Note: If you use asset_path() here, your compiled bootstrap_and_overrides.css will not +// have the proper paths. So for now we use the absolute path. +@fontAwesomeEotPath: asset-path("fontawesome-webfont.eot"); +@fontAwesomeEotPath_iefix: asset-path("fontawesome-webfont.eot#iefix"); +@fontAwesomeWoffPath: asset-path("fontawesome-webfont.woff"); +@fontAwesomeTtfPath: asset-path("fontawesome-webfont.ttf"); +@fontAwesomeSvgPath: asset-path("fontawesome-webfont.svg"); + +// Font Awesome +@import "fontawesome"; + +// Glyphicons +//@import "twitter/bootstrap/sprites.less"; + +// Your custom LESS stylesheets goes here +// +// Since bootstrap was imported above you have access to its mixins which +// you may use and inherit here +// +// If you'd like to override bootstrap's own variables, you can do so here as well +// See http://twitter.github.com/bootstrap/customize.html#variables for their names and documentation +// +// Example: +// @linkColor: #ff0000; +@navbarBackground: #000000; \ No newline at end of file diff --git a/app/assets/stylesheets/home.css.scss b/app/assets/stylesheets/home.css.scss new file mode 100644 index 00000000..f0ddc684 --- /dev/null +++ b/app/assets/stylesheets/home.css.scss @@ -0,0 +1,3 @@ +// 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/ diff --git a/app/assets/stylesheets/jquery-ui-1.9.2.custom.css b/app/assets/stylesheets/jquery-ui-1.9.2.custom.css new file mode 100644 index 00000000..0234adb1 --- /dev/null +++ b/app/assets/stylesheets/jquery-ui-1.9.2.custom.css @@ -0,0 +1,325 @@ +/*! jQuery UI - v1.9.2 - 2012-12-28 +* http://jqueryui.com +* Includes: jquery.ui.core.css, jquery.ui.datepicker.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande%2CLucida%20Sans%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=5px&bgColorHeader=5c9ccc&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=55&borderColorHeader=4297d7&fcHeader=ffffff&iconColorHeader=d8e7f3&bgColorContent=fcfdfd&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=a6c9e2&fcContent=222222&iconColorContent=469bdd&bgColorDefault=dfeffc&bgTextureDefault=02_glass.png&bgImgOpacityDefault=85&borderColorDefault=c5dbec&fcDefault=2e6e9e&iconColorDefault=6da8d5&bgColorHover=d0e5f5&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=79b7e7&fcHover=1d5987&iconColorHover=217bc0&bgColorActive=f5f8f9&bgTextureActive=06_inset_hard.png&bgImgOpacityActive=100&borderColorActive=79b7e7&fcActive=e17009&iconColorActive=f9bd01&bgColorHighlight=fbec88&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=fad42e&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px +* Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; } +.ui-helper-clearfix:after { clear: both; } +.ui-helper-clearfix { zoom: 1; } +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } +.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +} +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Lucida Grande,Lucida Sans,Arial,sans-serif; font-size: 1.1em; } +.ui-widget .ui-widget { font-size: 1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande,Lucida Sans,Arial,sans-serif; font-size: 1em; } +.ui-widget-content { border: 1px solid #a6c9e2; background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #222222; } +.ui-widget-content a { color: #222222; } +.ui-widget-header { border: 1px solid #4297d7; background: #5c9ccc url(images/ui-bg_gloss-wave_55_5c9ccc_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } +.ui-widget-header a { color: #ffffff; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #c5dbec; background: #dfeffc url(images/ui-bg_glass_85_dfeffc_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #2e6e9e; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2e6e9e; text-decoration: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #79b7e7; background: #d0e5f5 url(images/ui-bg_glass_75_d0e5f5_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1d5987; } +.ui-state-hover a, .ui-state-hover a:hover, .ui-state-hover a:link, .ui-state-hover a:visited { color: #1d5987; text-decoration: none; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #79b7e7; background: #f5f8f9 url(images/ui-bg_inset-hard_100_f5f8f9_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #e17009; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #e17009; text-decoration: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fad42e; background: #fbec88 url(images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; color: #363636; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; } +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } +.ui-state-disabled .ui-icon { filter:Alpha(Opacity=35); } /* For IE8 - See #6059 */ + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_469bdd_256x240.png); } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_469bdd_256x240.png); } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_d8e7f3_256x240.png); } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_6da8d5_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_217bc0_256x240.png); } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_f9bd01_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-on { background-position: -96px -144px; } +.ui-icon-radio-off { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -khtml-border-top-left-radius: 5px; border-top-left-radius: 5px; } +.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; -khtml-border-top-right-radius: 5px; border-top-right-radius: 5px; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; -khtml-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; -khtml-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; } + +/* Overlays */ +.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .3;filter:Alpha(Opacity=30); } +.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .3;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } \ No newline at end of file diff --git a/app/assets/stylesheets/osem.css b/app/assets/stylesheets/osem.css new file mode 100644 index 00000000..56bb4479 --- /dev/null +++ b/app/assets/stylesheets/osem.css @@ -0,0 +1,102 @@ +html, body,.container,.content { + height: 100%; +} + +#push, +#footer { + height: 60px; +} + +.container, .content { + position: relative; +} +#inner-content { + padding-top: 60px; +} + +#wrap { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -60px; +} + +#footer { + position: relative; + background-color: #ffffff; +} +.navbar-inner { + background: #299a0b; /* Old browsers */ + background: -moz-linear-gradient(top, #299a0b 0%, #299a0b 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#299a0b), color-stop(100%,#299a0b)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #299a0b 0%,#299a0b 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #299a0b 0%,#299a0b 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(top, #299a0b 0%,#299a0b 100%); /* IE10+ */ + background: linear-gradient(to bottom, #299a0b 0%,#299a0b 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#299a0b', endColorstr='#299a0b',GradientType=0 ); /* IE6-9 */ +} + +.navbar .nav .active > a, .navbar .nav .active > a:hover { + background-color: #DFE0DF; +} + +.navbar .divider-vertical { + background-color: #b4e391; + border-right: 1px solid #eab92d; +} + +.navbar-fixed-top .brand { + color: #ffffff; + text-shadow:none; +} + +.navbar .nav > li > a { + float: none; + padding: 10px 15px 10px; + color: white; + text-decoration: none; + text-shadow: none; +} + +.center { + margin:0 auto; + float:none; +} + +.center-text { + text-align: center +} + +textarea { + -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */ + -moz-box-sizing: border-box; /* Firefox, other Gecko */ + box-sizing: border-box; /* Opera/IE 8+ */ + width:100%; +} + +.mainbutton { + background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #9dce2c), color-stop(1, #8cb82b) ); + background:-moz-linear-gradient( center top, #9dce2c 5%, #8cb82b 100% ); + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#9dce2c', endColorstr='#8cb82b'); + background-color:#9dce2c; + -moz-border-radius:6px; + -webkit-border-radius:6px; + border-radius:6px; + border:1px solid #83c41a; + display:inline-block; + color:#ffffff; + font-family:Arial; + font-size:20px; + font-weight:bold; + padding:6px 24px; + text-decoration:none; + text-shadow:1px 1px 9px #689324; +}.mainbutton:hover { + background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #8cb82b), color-stop(1, #9dce2c) ); + background:-moz-linear-gradient( center top, #8cb82b 5%, #9dce2c 100% ); + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#8cb82b', endColorstr='#9dce2c'); + background-color:#8cb82b; + }.mainbutton:active { + position:relative; + top:1px; + } diff --git a/app/controllers/admin/callforpapers_controller.rb b/app/controllers/admin/callforpapers_controller.rb new file mode 100644 index 00000000..c4534af7 --- /dev/null +++ b/app/controllers/admin/callforpapers_controller.rb @@ -0,0 +1,28 @@ +class Admin::CallforpapersController < ApplicationController + before_filter :verify_organizer + layout "admin" + + def show + @cfp = @conference.call_for_papers + if @cfp.nil? + @cfp = CallForPapers.new + end + end + + def update + @cfp = @conference.call_for_papers + @cfp.update_attributes(params[:call_for_papers]) + redirect_to(admin_conference_cfp_info_path(:id => @conference.short_title), :notice => 'Call for Papers was successfully updated.') + + end + + def create + @cfp = CallForPapers.new(params[:call_for_papers]) + @conference.call_for_papers = @cfp + if @cfp.save + redirect_to(admin_conference_cfp_info_path(:id => @conference.short_title), :notice => 'Call for Papers was successfully updated.') + else + redirect_to(admin_conference_cfp_info_path(:id => @conference.short_title), :error => 'Call for Papers failed.') + end + end +end diff --git a/app/controllers/admin/conference_controller.rb b/app/controllers/admin/conference_controller.rb new file mode 100644 index 00000000..763e9b7d --- /dev/null +++ b/app/controllers/admin/conference_controller.rb @@ -0,0 +1,36 @@ +class Admin::ConferenceController < ApplicationController + before_filter :verify_organizer + layout "admin" + + def index + @conferences = Conference.all + if @conferences.count == 0 + redirect_to new_admin_conference_path + return + end + end + + def new + @conference = Conference.new + end + + def create + @conference = Conference.new(params[:conference]) + if @conference.save + redirect_to(admin_conference_path(:id => @conference.short_title), :notice => 'Conference was successfully created.') + else + render :action => "new" + end + end + + def update + @conference = Conference.find_all_by_short_title(params[:id]).first + @conference.update_attributes(params[:conference]) + flash[:notice] = "Updated Conference" + redirect_to(admin_conference_path(:id => @conference.short_title), :notice => 'Conference was successfully updated.') + end + + def show + @conference = Conference.find_all_by_short_title(params[:id]).first + end +end diff --git a/app/controllers/admin/events_controller.rb b/app/controllers/admin/events_controller.rb new file mode 100644 index 00000000..764b752a --- /dev/null +++ b/app/controllers/admin/events_controller.rb @@ -0,0 +1,41 @@ +class Admin::EventsController < ApplicationController + before_filter :verify_organizer + layout "admin" + + def index + @events = @conference.events + end + + def show + @event = @conference.events.find(params[:id]) + @comments = @event.root_comments + @comment_count = @event.comment_threads.count + end + + def edit + @event_types = @conference.event_types + @event = Event.find_by_id(params[:id]) + @person = @event.submitter + @url = edit_admin_conference_event_path(@conference.short_title, @event) + end + + def comment + event = @conference.events.find_by_id(params[:id]) + comment = Comment.build_from(event, current_user.id, params[:comment]) + comment.save! + if !params[:parent].nil? + comment.move_to_child_of(params[:parent]) + end + + redirect_to admin_conference_event_path(:conference_id => @conference.short_title, :id => params[:id]) + end + def create + + end + + def update_state + event = Event.find(params[:id]) + event.send(:"#{params[:transition]}!", :send_mail => params[:send_mail]) + redirect_to(admin_conference_events_path(:conference_id => @conference.short_title), :notice => "Updated state") + end +end diff --git a/app/controllers/admin/eventtype_controller.rb b/app/controllers/admin/eventtype_controller.rb new file mode 100644 index 00000000..64aa3939 --- /dev/null +++ b/app/controllers/admin/eventtype_controller.rb @@ -0,0 +1,17 @@ +class Admin::EventtypeController < ApplicationController + before_filter :verify_organizer + layout "admin" + + def show + render :event_type_list + end + + def update + begin + @conference.update_attributes!(params[:conference]) + redirect_to(admin_conference_eventtype_list_path(:conference_id => @conference.short_title), :notice => 'Event types were successfully updated.') + rescue Exception => e + redirect_to(admin_conference_eventtype_list_path(:conference_id => @conference.short_title), :alert => 'Event types update failed: #{e.message}') + end + end +end \ No newline at end of file diff --git a/app/controllers/admin/people_controller.rb b/app/controllers/admin/people_controller.rb new file mode 100644 index 00000000..d31f4c2d --- /dev/null +++ b/app/controllers/admin/people_controller.rb @@ -0,0 +1,24 @@ +class Admin::PeopleController < ApplicationController + before_filter :verify_organizer + layout "admin" + + def index + @people = Person.all + end + + def create + + end + + def show + @person = Person.find(params[:id]) + end + + def update + + end + + def delete + + end +end diff --git a/app/controllers/admin/registrations_controller.rb b/app/controllers/admin/registrations_controller.rb new file mode 100644 index 00000000..ee92e8c1 --- /dev/null +++ b/app/controllers/admin/registrations_controller.rb @@ -0,0 +1,16 @@ +class Admin::RegistrationsController < ApplicationController + before_filter :verify_organizer + layout "admin" + + def show + session[:return_to] ||= request.referer + @pdf_filename = "#{@conference.title}.pdf" + @registrations = @conference.registrations.all(:joins => :person, + :order => "people.last_name ASC", + :select => "registrations.*, + people.last_name AS last_name, + people.first_name AS first_name, + people.public_name AS public_name, + people.email AS email") + end +end \ No newline at end of file diff --git a/app/controllers/admin/rooms_controller.rb b/app/controllers/admin/rooms_controller.rb new file mode 100644 index 00000000..b736b22f --- /dev/null +++ b/app/controllers/admin/rooms_controller.rb @@ -0,0 +1,18 @@ +class Admin::RoomsController < ApplicationController + before_filter :verify_organizer + layout "admin" + + def show + render :rooms_list + end + + def update + if @conference.update_attributes(params[:conference]) + redirect_to(admin_conference_rooms_list_path(:conference_id => @conference.short_title), :notice => 'Rooms were successfully updated.') + else + redirect_to(admin_conference_rooms_list_path(:conference_id => @conference.short_title), :notice => 'Room update failed.') + end + + end + +end diff --git a/app/controllers/admin/tracks_controller.rb b/app/controllers/admin/tracks_controller.rb new file mode 100644 index 00000000..88798893 --- /dev/null +++ b/app/controllers/admin/tracks_controller.rb @@ -0,0 +1,18 @@ +class Admin::TracksController < ApplicationController + before_filter :verify_organizer + layout "admin" + + def show + render :tracks_list + end + + def update + if @conference.update_attributes(params[:conference]) + redirect_to(admin_conference_tracks_list_path(:conference_id => @conference.short_title), :notice => 'Tracks were successfully updated.') + else + redirect_to(admin_conference_tracks_list_path(:conference_id => @conference.short_title), :notice => 'Tracks update failed.') + end + + end + +end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb new file mode 100644 index 00000000..35ab58d4 --- /dev/null +++ b/app/controllers/admin/users_controller.rb @@ -0,0 +1,20 @@ +class Admin::UsersController < ApplicationController + before_filter :verify_admin + layout "admin" + + def index + @users = User.all(:joins => :person, + :order => "people.last_name ASC", + :select => "users.*, + people.last_name AS last_name, + people.first_name AS first_name, + people.public_name AS public_name, + people.email AS email") + end + + def update + user = User.find(params[:id]) + user.update_attributes!(params[:user]) + redirect_to admin_users_path, :notice => "Updated #{user.email}" + end +end diff --git a/app/controllers/admin/venue_controller.rb b/app/controllers/admin/venue_controller.rb new file mode 100644 index 00000000..d8ad1c5d --- /dev/null +++ b/app/controllers/admin/venue_controller.rb @@ -0,0 +1,24 @@ +class Admin::VenueController < ApplicationController + before_filter :verify_organizer + layout "admin" + + def index + end + + def update + @venue = @conference.venue + venue_params = params[:venue] + @venue.name = venue_params[:name] + @venue.address= venue_params[:address] + @venue.website = venue_params[:website] + @venue.description = venue_params[:description] + @venue.save + redirect_to(admin_conference_venue_info_path(:conference_id => @conference.short_title), :notice => 'Venue was successfully updated.') + end + + def show + @venue = @conference.venue + render :venue_info + end + +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 00000000..d45387fa --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,42 @@ +class ApplicationController < ActionController::Base + include ApplicationHelper + + protect_from_forgery + + def verify_user + :authenticate_user! + + if (current_user.nil?) + redirect_to '/accounts/sign_in' + return + end + + @conference = Conference.find_all_by_short_title(params[:conference_id]).first + end + + def organizer_or_admin? + has_role?(current_user, 'admin') || has_role?(current_user, 'organizer') + end + + def verify_organizer + verify_user + + ## Todo simplify this + redirect_to '/' unless has_role?(current_user, 'admin') || has_role?(current_user, 'organizer') + end + + def verify_admin + verify_user + + redirect_to '/' unless has_role?(current_user, 'admin') + end + + def current_ability + @current_ability ||= AdminAbility.new(current_user) + end + + rescue_from CanCan::AccessDenied do |exception| + Rails.logger.debug("Access denied!") + redirect_to '/', :alert => exception.message + end +end diff --git a/app/controllers/conference_registration_controller.rb b/app/controllers/conference_registration_controller.rb new file mode 100644 index 00000000..50b8d3d5 --- /dev/null +++ b/app/controllers/conference_registration_controller.rb @@ -0,0 +1,51 @@ +class ConferenceRegistrationController < ApplicationController + before_filter :verify_user + + def register + # TODO Figure out how to change the route's id from :id to :conference_id + @conference = Conference.find_all_by_short_title(params[:id]).first + @person = current_user.person + @registration = @person.registrations.where(:conference_id => @conference.id).first + @registered = true + if @registration.nil? + @registered = false + @registration = @person.registrations.new(:conference_id => @conference.id) + end + end + + def update + conference = Conference.find_all_by_short_title(params[:id]).first + person = current_user.person + registration = person.registrations.where(:conference_id => conference.id).first + update_registration = true + begin + if registration.nil? + update_registration = false + person.update_attributes(params[:registration][:person_attributes]) + params[:registration].delete :person_attributes + registration = person.registrations.new(params[:registration]) + registration.conference_id = conference.id + registration.save! + else + registration.update_attributes!(params[:registration]) + end + rescue Exception => e + redirect_to(register_conference_path(:id => conference.short_title), :alert => 'Registration failed:' + e.message) + return + end + + redirect_message = "You are now registered." + if update_registration + redirect_message = "Registration updated." + end + redirect_to(register_conference_path(:id => conference.short_title), :notice => redirect_message) + end + + def unregister + conference = Conference.find_all_by_short_title(params[:id]).first + person = current_user.person + registration = person.registrations.where(:conference_id => conference.id).first + registration.destroy + redirect_to :root + end +end diff --git a/app/controllers/event_attachments_controller.rb b/app/controllers/event_attachments_controller.rb new file mode 100644 index 00000000..95248f0c --- /dev/null +++ b/app/controllers/event_attachments_controller.rb @@ -0,0 +1,97 @@ +class EventAttachmentsController < ApplicationController + before_filter :verify_user + skip_before_filter :verify_user, :only => [:show] + + def index + @proposal = current_user.person.events.find(params[:proposal_id]) + @uploads = @proposal.event_attachments + + respond_to do |format| + format.html # index.html.erb + format.json { render json: @uploads.map{|upload| upload.to_jq_upload } } + end + end + + def show + upload = EventAttachment.find(params[:id]) + if upload.public? + send_file upload.attachment.path + return + end + + if current_user.nil? + verify_user + return + end + + if organizer_or_admin? || current_user.person == upload.event.submitter + send_file upload.attachment.path + else + raise ActionController::RoutingError.new('Not Found') + end + end + + def new + @upload = EventAttachment.new + + respond_to do |format| + format.html # new.html.erb + format.json { render json: @upload } + end + end + + def edit + @upload = EventAttachment.find(params[:id]) + end + + def create + params[:event_attachment][:title] = params[:title][0] + params[:event_attachment][:public] = false + params[:event_attachment][:event_id] = params[:proposal_id] + + if params.has_key?(:public) + params[:event_attachment][:public] = true + end + @upload = EventAttachment.new(params[:event_attachment]) + + respond_to do |format| + if @upload.save + format.html { + render :json => [@upload.to_jq_upload].to_json, + :content_type => 'text/html', + :layout => false + } + format.json { render json: [@upload.to_jq_upload].to_json, status: :created, + location: conference_proposal_event_attachment_path(@upload.event.conference.short_title, @upload.event, @upload) } + else + format.html { render action: "new" } + format.json { render json: @upload.errors, status: :unprocessable_entity } + end + end + end + + def update + @upload = EventAttachment.find(params[:proposal_id]) + + respond_to do |format| + if @upload.update_attributes(params[:upload]) + format.html { redirect_to @upload, notice: 'Upload was successfully updated.' } + format.json { head :no_content } + else + format.html { render action: "edit" } + format.json { render json: @upload.errors, status: :unprocessable_entity } + end + end + end + + def destroy + @proposal = current_user.person.events.find(params[:proposal_id]) + @upload = @proposal.event_attachments.find(params[:id]) + @upload.destroy + + respond_to do |format| + format.html { redirect_to uploads_url } + format.json { head :no_content } + end + end +end \ No newline at end of file diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb new file mode 100644 index 00000000..089c8d49 --- /dev/null +++ b/app/controllers/home_controller.rb @@ -0,0 +1,7 @@ +class HomeController < ApplicationController + def index + @today = Date.current + @conferences = Conference.where("start_date >= ?", @today) + end + +end diff --git a/app/controllers/proposal_controller.rb b/app/controllers/proposal_controller.rb new file mode 100644 index 00000000..15bb60a4 --- /dev/null +++ b/app/controllers/proposal_controller.rb @@ -0,0 +1,97 @@ +class ProposalController < ApplicationController + before_filter :verify_user + + def index + @person = current_user.person + @events = @person.proposals @conference + end + + def destroy + current_user.person.withdraw_proposal(params[:id]) + redirect_to(conference_proposal_index_path(:conference_id => @conference.short_title), :alert => 'Proposal withdrawn.') + end + + def new + @url = conference_proposal_index_path(@conference.short_title) + @event = Event.new + @event_types = @conference.event_types + @person = current_user.person + end + + def edit + @url = conference_proposal_path(@conference.short_title, params[:id]) + @person = current_user.person + @event_types = @conference.event_types + @event = @person.events.find_by_id(params[:id]) + @attachments = @event.event_attachments + + if @event.nil? + redirect_to(conference_proposal_index_path(:conference_id => @conference.short_title), :alert => 'Invalid proposal.') + end + end + + def update + person = current_user.person + session[:return_to] ||= request.referer + submitter = params[:person] + + params[:event].delete :people_attributes + params[:event].delete :person + + if submitter[:public_name] != person.public_name || submitter[:biography] != person.biography + person.update_attributes(submitter) + end + + event = Event.find_by_id(params[:id]) + + if event.update_attributes!(params[:event]) + redirect_to(conference_proposal_index_path(:conference_id => @conference.short_title), :notice => "'#{event.title}' was successfully updated.") + else + redirect_to session[:return_to], :alert => "'#{event.title}' was NOT updated!" + end + end + + def create + person = current_user.person + session[:return_to] ||= request.referer + + event_params = params[:event] + submitter = params[:person] + params[:event].delete :person + + # First, update the submitter's info, if they've changed anything + if submitter[:public_name] != person.public_name || submitter[:biography] != person.biography + person.update_attributes(submitter) + end + + @event = Event.new(event_params) + @event.conference = @conference + @event.event_people.new(:person => person, + :event_role => "submitter") + @event.event_people.new(:person => person, + :event_role => "speaker") + + begin + @event.save! + rescue Exception => e + @url = conference_proposal_index_path(@conference.short_title) + @event_types = @conference.event_types + @person = current_user.person + + flash[:error] = "Could not submit proposal: #{e.message}" + render :action => 'new' + return + end + + registration = person.registrations.where(:conference_id => @conference.id).first + if registration.nil? + redirect_to(register_conference_path(@conference.short_title), :notice => 'Event was successfully submitted. You probably want to register for the conference now!') + else + redirect_to(conference_proposal_index_path(:conference_id => @conference.short_title), :notice => 'Event was successfully submitted.') + end + end + + def show + + end +end diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb new file mode 100644 index 00000000..4d97851a --- /dev/null +++ b/app/controllers/registrations_controller.rb @@ -0,0 +1,52 @@ +class RegistrationsController < Devise::RegistrationsController + def update + @user = User.find(current_user.id) + email_changed = false + + if !params[:user][:email].nil? + if @user.email != params[:user][:email] + email_changed = true + else + params[:user].delete :email + end + end + + password_changed = false + if !params[:user][:password].nil? + if !params[:user][:password].empty? + password_changed = true + else + params[:user].delete :password + params[:user].delete :password_confirmation + params[:user].delete :current_password + end + end + + + successfully_updated = if email_changed or password_changed + @user.update_with_password(params[:user]) + else + @user.update_without_password(params[:user]) + end + + if successfully_updated + set_flash_message :notice, :updated + # Sign in the user bypassing validation in case his password changed + sign_in @user, :bypass => true + redirect_to after_update_path_for(@user) + else + render "edit" + end + end + + protected + + def after_update_path_for(resource) + edit_user_registration_path(resource) + end + + def after_sign_up_path_for(resource) + edit_user_registration_path(resource) + end + +end \ No newline at end of file diff --git a/app/helpers/admin/call_for_papers_helper.rb b/app/helpers/admin/call_for_papers_helper.rb new file mode 100644 index 00000000..6e8ba54b --- /dev/null +++ b/app/helpers/admin/call_for_papers_helper.rb @@ -0,0 +1,2 @@ +module Admin::CallForPapersHelper +end diff --git a/app/helpers/admin/conference_helper.rb b/app/helpers/admin/conference_helper.rb new file mode 100644 index 00000000..c17678c0 --- /dev/null +++ b/app/helpers/admin/conference_helper.rb @@ -0,0 +1,2 @@ +module Admin::ConferenceHelper +end diff --git a/app/helpers/admin/people_helper.rb b/app/helpers/admin/people_helper.rb new file mode 100644 index 00000000..a6e7e7fa --- /dev/null +++ b/app/helpers/admin/people_helper.rb @@ -0,0 +1,2 @@ +module Admin::PeopleHelper +end diff --git a/app/helpers/admin/users_helper.rb b/app/helpers/admin/users_helper.rb new file mode 100644 index 00000000..5995c2aa --- /dev/null +++ b/app/helpers/admin/users_helper.rb @@ -0,0 +1,2 @@ +module Admin::UsersHelper +end diff --git a/app/helpers/admin/venue_helper.rb b/app/helpers/admin/venue_helper.rb new file mode 100644 index 00000000..409948c7 --- /dev/null +++ b/app/helpers/admin/venue_helper.rb @@ -0,0 +1,2 @@ +module Admin::VenueHelper +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 00000000..ed736e54 --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,43 @@ +module ApplicationHelper + + def add_association_link(association_name, form_builder, div_class, html_options = {}) + link_to_add_association "Add " + association_name.to_s.singularize, form_builder, div_class, html_options.merge(:class => "assoc btn btn-success") + end + + def remove_association_link(association_name, form_builder) + link_to_remove_association("Remove " + association_name.to_s.singularize, form_builder, :class => "assoc btn btn-danger") + tag(:hr) + end + + def dynamic_association(association_name, title, form_builder, options = {}) + render "shared/dynamic_association", :association_name => association_name, :title => title, :f => form_builder, :hint => options[:hint] + end + + def has_role?(current_user, role) + return !!current_user.role?(role.to_s.camelize) + end + + # TODO Output better html + def format_comments(comment, padding = 0) + result = "" + result += "
" + result += "
" + result += "#{comment.user.person.public_name} #{comment.created_at}

" + result += comment.body + result += "
Reply

" + result += "
" + result += "
" + result += "" + result += "" + result += "" + result += "" + result += "
" + result += "
" + #result += edit_admin_conference_event_path(@conference.short_title, @event) + comment.children.each do |child| + result += format_comments(child, 50) + result += "
" + end + + result + end +end diff --git a/app/helpers/home_helper.rb b/app/helpers/home_helper.rb new file mode 100644 index 00000000..23de56ac --- /dev/null +++ b/app/helpers/home_helper.rb @@ -0,0 +1,2 @@ +module HomeHelper +end diff --git a/app/mailers/.gitkeep b/app/mailers/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/app/models/.gitkeep b/app/models/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/app/models/ability.rb b/app/models/ability.rb new file mode 100644 index 00000000..58929d7a --- /dev/null +++ b/app/models/ability.rb @@ -0,0 +1,28 @@ +class Ability + include CanCan::Ability + + def initialize(user) + # Define abilities for the passed in user here. For example: + # + # user ||= User.new # guest user (not logged in) + # if user.admin? + # can :manage, :all + # else + # can :read, :all + # end + # + # The first argument to `can` is the action you are giving the user permission to do. + # If you pass :manage it will apply to every action. Other common actions here are + # :read, :create, :update and :destroy. + # + # The second argument is the resource the user can perform the action on. If you pass + # :all it will apply to every resource. Otherwise pass a Ruby class of the resource. + # + # The third argument is an optional hash of conditions to further filter the objects. + # For example, here the user can only update published articles. + # + # can :update, Article, :published => true + # + # See the wiki for details: https://github.com/ryanb/cancan/wiki/Defining-Abilities + end +end diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb new file mode 100644 index 00000000..8aff497a --- /dev/null +++ b/app/models/admin_ability.rb @@ -0,0 +1,17 @@ +class AdminAbility + include CanCan::Ability + + def initialize(user) + @user = user || User.new # for guest + @user.get_roles.each { |role| send(role.name.downcase) } + end + + def organizer + can :manage, Event + end + + def admin + organizer + can :manage, :all + end +end diff --git a/app/models/call_for_papers.rb b/app/models/call_for_papers.rb new file mode 100644 index 00000000..f31a8127 --- /dev/null +++ b/app/models/call_for_papers.rb @@ -0,0 +1,7 @@ +class CallForPapers < ActiveRecord::Base + attr_accessible :start_date, :end_date, :hard_deadline, :description + belongs_to :conference + + validates_presence_of :start_date, :end_date, :hard_deadline + +end \ No newline at end of file diff --git a/app/models/comment.rb b/app/models/comment.rb new file mode 100644 index 00000000..8cccba85 --- /dev/null +++ b/app/models/comment.rb @@ -0,0 +1,48 @@ +class Comment < ActiveRecord::Base + acts_as_nested_set :scope => [:commentable_id, :commentable_type] + attr_accessible :commentable, :body, :user_id + validates_presence_of :body + validates_presence_of :user + + # NOTE: install the acts_as_votable plugin if you + # want user to vote on the quality of comments. + #acts_as_votable + + belongs_to :commentable, :polymorphic => true + + # NOTE: Comments belong to a user + belongs_to :user + + # Helper class method that allows you to build a comment + # by passing a commentable object, a user_id, and comment text + # example in readme + def self.build_from(obj, user_id, comment) + new \ + :commentable => obj, + :body => comment, + :user_id => user_id + end + + #helper method to check if a comment has children + def has_children? + self.children.any? + end + + # Helper class method to lookup all comments assigned + # to all commentable types for a given user. + scope :find_comments_by_user, lambda { |user| + where(:user_id => user.id).order('created_at DESC') + } + + # Helper class method to look up all comments for + # commentable class name and commentable id. + scope :find_comments_for_commentable, lambda { |commentable_str, commentable_id| + where(:commentable_type => commentable_str.to_s, :commentable_id => commentable_id).order('created_at DESC') + } + + # Helper class method to look up a commentable object + # given the commentable class name and id + def self.find_commentable(commentable_str, commentable_id) + commentable_str.constantize.find(commentable_id) + end +end \ No newline at end of file diff --git a/app/models/conference.rb b/app/models/conference.rb new file mode 100644 index 00000000..6216cfda --- /dev/null +++ b/app/models/conference.rb @@ -0,0 +1,87 @@ +class Conference < ActiveRecord::Base + attr_accessible :title, :short_title, :social_tag, :contact_email, :timezone, :html_export_path, + :start_date, :end_date, :rooms_attributes, :tracks_attributes, :cfp_open, :registration_open, + :event_types_attributes + + has_one :call_for_papers, :dependent => :destroy + has_many :events, :dependent => :destroy + has_many :event_types, :dependent => :destroy + has_many :tracks, :dependent => :destroy + has_many :rooms, :dependent => :destroy + has_many :registrations, :dependent => :destroy + + belongs_to :venue + + accepts_nested_attributes_for :rooms, :reject_if => proc {|r| r["name"].blank?}, :allow_destroy => true + accepts_nested_attributes_for :tracks, :reject_if => proc {|r| r["name"].blank?}, :allow_destroy => true + accepts_nested_attributes_for :venue + accepts_nested_attributes_for :event_types, :allow_destroy => true + + validates_presence_of :title, + :short_title, + :social_tag + validates_uniqueness_of :short_title + validates_format_of :short_title, :with => /^[a-zA-Z0-9_-]*$/ + before_create :generate_guid + before_create :create_venue + + + def self.current + self.order("created_at DESC").first + end + + def date_range_string + startstr = "Unknown - " + endstr = "Unknown" + if start_date.month == end_date.month && start_date.year == end_date.year + startstr = start_date.strftime("%B %d - ") + endstr = end_date.strftime("%d, %Y") + elsif start_date.month != end_date.month && start_date.year == end_date.year + startstr = start_date.strftime("%B %d - ") + endstr = end_date.strftime("%B %d, %Y") + else + startstr = start_date.strftime("%B %d, %Y - ") + endstr = end_date.strftime("%B %d, %Y") + end + + result = startstr + endstr + result + end + + def user_registered? user + return nil if user.nil? + return nil if user.person.nil? + + if self.registrations.where(:person_id => user.person.id).count == 0 + Rails.logger.debug("Returning false") + false + else + Rails.logger.debug("Returning true") + true + end + end + + def cfp_open? + today = Date.current + cfp = self.call_for_papers + if !cfp.nil? && (cfp.start_date.. cfp.end_date).cover?(today) + return true + end + + return false + end + private + + def create_venue + self.venue_id = Venue.create.id + true + end + + def generate_guid + begin + guid = SecureRandom.urlsafe_base64 + end while Person.where(:guid => guid).exists? + self.guid = guid + end + +end \ No newline at end of file diff --git a/app/models/event.rb b/app/models/event.rb new file mode 100644 index 00000000..fc7fc5dc --- /dev/null +++ b/app/models/event.rb @@ -0,0 +1,101 @@ +class Event < ActiveRecord::Base + include ActiveRecord::Transitions + + attr_accessible :title, :subtitle, :abstract, :description, :event_type_id, :people_attributes, :person, + :proposal_additional_speakers + acts_as_commentable + + has_many :event_people, :dependent => :destroy + has_many :event_attachments, :dependent => :destroy + has_many :people, :through => :event_people + belongs_to :event_type + + belongs_to :track + belongs_to :room + belongs_to :conference + + accepts_nested_attributes_for :event_people + accepts_nested_attributes_for :event_attachments, :allow_destroy => true, :reject_if => :all_blank + accepts_nested_attributes_for :people + before_create :generate_guid + validate :abstract_limit + + state_machine :initial => :new do + state :new + state :review + state :withdrawn + state :accepted + state :unconfirmed + state :confirmed + state :canceled + state :rejected + + event :start_review do + transitions :to => :review, :from => [:new, :rejected] + end + event :withdraw do + transitions :to => :withdrawn, :from => [:new, :review, :unconfirmed] + end + event :accept do + transitions :to => :unconfirmed, :from => [:new, :review], :on_transition => :process_acceptance + end + event :unconfirm do + transitions :to => :review, :from=>[:confirmed] + end + event :confirm do + transitions :to => :confirmed, :from => :unconfirmed + end + event :cancel do + transitions :to => :canceled, :from => [:unconfirmed, :confirmed] + end + event :reject do + transitions :to => :rejected, :from => [:new, :review], :on_transition => :process_rejection + end + end + + def submitter + result = self.event_people.where(:event_role => "submitter").first + if !result.nil? + result.person + else + nil + end + end + + def transition_possible?(transition) + self.class.state_machine.events_for(self.current_state).include?(transition) + end + + def process_acceptance(options) +# if options[:send_mail] + # self.event_people.presenter.each do |event_person| + # event_person.generate_token! + # SelectionNotification.acceptance_notification(event_person).deliver + # end + # end + + end + + def abstract_word_count + if self.abstract.nil? + 0 + else + self.abstract.split.size + end + end + private + + def abstract_limit + if self.abstract.split.size > 250 + errors.add(:abstract, "cannot have more than 250 words") + end + end + + def generate_guid + begin + guid = SecureRandom.urlsafe_base64 + end while self.class.where(:guid => guid).exists? + self.guid = guid + end + +end \ No newline at end of file diff --git a/app/models/event_attachment.rb b/app/models/event_attachment.rb new file mode 100644 index 00000000..9d33fa41 --- /dev/null +++ b/app/models/event_attachment.rb @@ -0,0 +1,28 @@ +class EventAttachment < ActiveRecord::Base + belongs_to :event + scope :public, where(:public => true) + attr_accessible :public, :attachment, :event_id, :title + + has_attached_file :attachment, :path => ":rails_root/storage/:rails_env/attachments/:id/:style/:basename.:extension" + include Rails.application.routes.url_helpers + + def to_jq_upload + { + "name" => read_attribute(:attachment_file_name), + "size" => read_attribute(:attachment_file_size), + "title" => read_attribute(:title), + "public" => read_attribute(:public), + #"url" => attachment.url(:original), + "url" => conference_proposal_event_attachment_path(self.event.conference.short_title, self.event_id, self.id), + "delete_url" => conference_proposal_event_attachment_path(self.event.conference.short_title, self.event_id, self.id), + "delete_type" => "DELETE" + } + + end + #:path => ":rails_root/public/system/:attachment/:id/:style/:filename", + # :url => "/system/:attachment/:id/:style/:filename" + + #has_paper_trail :meta => {:associated_id => :event_id, :associated_type => "Event"} + + +end diff --git a/app/models/event_person.rb b/app/models/event_person.rb new file mode 100644 index 00000000..ba0721a2 --- /dev/null +++ b/app/models/event_person.rb @@ -0,0 +1,8 @@ +class EventPerson < ActiveRecord::Base + attr_accessible :event, :person, :person_id, :event_role + # TODO Do we need these roles? + ROLES = [["Speaker","speaker"], ["Submitter","submitter"], ["Moderator","moderator"]] + + belongs_to :event + belongs_to :person +end \ No newline at end of file diff --git a/app/models/event_type.rb b/app/models/event_type.rb new file mode 100644 index 00000000..49afdbbb --- /dev/null +++ b/app/models/event_type.rb @@ -0,0 +1,5 @@ +class EventType < ActiveRecord::Base + attr_accessible :title, :length + + belongs_to :conference +end diff --git a/app/models/person.rb b/app/models/person.rb new file mode 100644 index 00000000..173f0088 --- /dev/null +++ b/app/models/person.rb @@ -0,0 +1,71 @@ +class Person < ActiveRecord::Base + attr_accessible :email, :first_name, :last_name, :public_name, :biography, :company + + has_many :event_people, :dependent => :destroy + has_many :events, :through => :event_people, :uniq => true + has_many :registrations, :dependent => :destroy + validates :first_name, :presence => true + validates :last_name, :presence => true + validate :biography_limit + + before_create :generate_guid + before_save :set_public_name + + def to_s + if self.public_name.empty? + self.first_name + " " + self.last_name + else + self.public_name + end + end + + def withdraw_proposal id + proposal = self.events.find_by_id(id) + if !proposal.nil? + proposal.withdraw + proposal.save + end + end + + def attending_conference? conference + Registration.where(:conference_id => conference.id, + :person_id => self.id).count + end + + def proposals conference + self.events.where("conference_id = ? AND state != ? AND state != ?", conference.id, "withdrawn", "rejected") + end + + def proposal_count conference + proposals(conference).count + end + + def biography_word_count + if self.biography.nil? + 0 + else + self.biography.split.size + end + end + + private + def biography_limit + if self.biography.split.size > 150 + errors.add(:abstract, "cannot have more than 150 words") + end + end + + def set_public_name + if public_name.empty? + self.public_name = "#{first_name} #{last_name}" + end + end + + def generate_guid + begin + guid = SecureRandom.urlsafe_base64 + end while Person.where(:guid => guid).exists? + self.guid = guid + end + +end \ No newline at end of file diff --git a/app/models/registration.rb b/app/models/registration.rb new file mode 100644 index 00000000..b8886570 --- /dev/null +++ b/app/models/registration.rb @@ -0,0 +1,9 @@ +class Registration < ActiveRecord::Base + belongs_to :person + belongs_to :conference + + attr_accessible :person_id, :conference_id, :attending_social_events, :attending_social_events_with_partner, + :using_affiliated_lodging, :arrival, :departure, :person_attributes + accepts_nested_attributes_for :person + +end \ No newline at end of file diff --git a/app/models/role.rb b/app/models/role.rb new file mode 100644 index 00000000..0fb24257 --- /dev/null +++ b/app/models/role.rb @@ -0,0 +1,4 @@ +class Role < ActiveRecord::Base + attr_accessible :name + has_and_belongs_to_many :users +end \ No newline at end of file diff --git a/app/models/room.rb b/app/models/room.rb new file mode 100644 index 00000000..ba68566e --- /dev/null +++ b/app/models/room.rb @@ -0,0 +1,18 @@ +class Room < ActiveRecord::Base + attr_accessible :name, :size, :public + + belongs_to :conference + has_many :events + + before_create :generate_guid + + private + + def generate_guid + begin + guid = SecureRandom.urlsafe_base64 + end while Person.where(:guid => guid).exists? + self.guid = guid + end + +end \ No newline at end of file diff --git a/app/models/track.rb b/app/models/track.rb new file mode 100644 index 00000000..7c6f685f --- /dev/null +++ b/app/models/track.rb @@ -0,0 +1,17 @@ +class Track < ActiveRecord::Base + attr_accessible :name, :description, :color + + belongs_to :conference + + before_create :generate_guid + + private + + def generate_guid + begin + guid = SecureRandom.urlsafe_base64 + end while Person.where(:guid => guid).exists? + self.guid = guid + end + +end \ No newline at end of file diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 00000000..9e262977 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,55 @@ +class User < ActiveRecord::Base + + # Include default devise modules. Others available are: + # :token_authenticatable, :confirmable, + # :lockable, :timeoutable and :omniauthable + devise :database_authenticatable, :registerable, + :recoverable, :rememberable, :trackable, :validatable + + has_and_belongs_to_many :roles + has_one :person + + attr_accessible :email, :password, :password_confirmation, :remember_me, :role_id, :role_ids, :person_attributes + accepts_nested_attributes_for :person + accepts_nested_attributes_for :roles + + before_save :setup_role + before_create :create_person + + def role?(role) + Rails.logger.debug("Checking role in user") + return !!self.roles.find_by_name(role.to_s.camelize) + end + + def get_roles + return self.roles + end + + def setup_role + if self.role_ids.empty? + self.role_ids = [1] + end + end + + def popup_details + details = "Sign-in Count
" + details += "#{self.sign_in_count}
" + details += "Current Sign-in
" + details += "#{self.current_sign_in_at}
" + details += "Last Sign-in
" + details += "#{self.last_sign_in_at}
" + details += "Current Sign-in IP
" + details += "#{self.current_sign_in_ip}
" + details += "Last Sign-in IP
" + details += "#{self.last_sign_in_ip}
" + details += "Created at
" + details += "#{self.created_at}
" + end + + private + def create_person + # TODO Search people for existing email address, add to their account + build_person(:email => self.email) + true + end +end diff --git a/app/models/venue.rb b/app/models/venue.rb new file mode 100644 index 00000000..e0251f7c --- /dev/null +++ b/app/models/venue.rb @@ -0,0 +1,14 @@ +class Venue < ActiveRecord::Base + has_many :conferences + before_create :generate_guid + + private + + def generate_guid + begin + guid = SecureRandom.urlsafe_base64 + end while Venue.where(:guid => guid).exists? + self.guid = guid + end + +end diff --git a/app/views/admin/callforpapers/show.html.haml b/app/views/admin/callforpapers/show.html.haml new file mode 100644 index 00000000..5b388a82 --- /dev/null +++ b/app/views/admin/callforpapers/show.html.haml @@ -0,0 +1,11 @@ +.container-fluid + .row-fluid + .span3 + = render 'admin/conference/sidebar', :activated => "Call for Papers" + .span9 + = semantic_form_for(@cfp, :url => admin_conference_cfp_update_path(@conference.short_title),:html => {:multipart => true}) do |f| + = f.input :start_date, :as => :string, :input_html => { :id => "conference-start-datepicker", :readonly => "readonly" } + = f.input :end_date, :as => :string, :input_html => { :id => "conference-end-datepicker", :readonly => "readonly" } + = f.input :hard_deadline, :as => :string, :input_html => { :id => "cfp-hard-datepicker", :readonly => "readonly" } + = f.input :description, :hint => "Welcome text for the Call for Papers" + = f.action :submit, :as => :button, :button_html => {:class => "btn btn-primary"} \ No newline at end of file diff --git a/app/views/admin/conference/_sidebar.html.haml b/app/views/admin/conference/_sidebar.html.haml new file mode 100644 index 00000000..cb8b4397 --- /dev/null +++ b/app/views/admin/conference/_sidebar.html.haml @@ -0,0 +1,26 @@ +.well.sidebar-nav + %ul.nav.nav-list + - if activated == "Conference" + %li.active= link_to "Conference", "#" + - else + %li= link_to "Conference", admin_conference_path(@conference.short_title) + - if activated == "Call for Papers" + %li.active= link_to "Call for Papers", "#" + - else + %li= link_to "Call for Papers", admin_conference_cfp_info_path(@conference.short_title) + - if activated == "Venue" + %li.active= link_to "Venue", "#" + - else + %li= link_to "Venue", admin_conference_venue_info_path(@conference.short_title) + - if activated == "Rooms" + %li.active= link_to "Rooms", "#" + - else + %li= link_to "Rooms", admin_conference_rooms_list_path(@conference.short_title) + - if activated == "Tracks" + %li.active= link_to "Tracks", "#" + - else + %li= link_to "Tracks", admin_conference_tracks_list_path(@conference.short_title) + - if activated == "Event Types" + %li.active= link_to "Event Types", "#" + - else + %li= link_to "Event Types", admin_conference_eventtype_list_path(@conference.short_title) \ No newline at end of file diff --git a/app/views/admin/conference/index.html.haml b/app/views/admin/conference/index.html.haml new file mode 100644 index 00000000..737680e7 --- /dev/null +++ b/app/views/admin/conference/index.html.haml @@ -0,0 +1,3 @@ +%ul + - @conferences.each do |conference| + %li= link_to conference.title, admin_conference_path(conference.short_title) diff --git a/app/views/admin/conference/new.html.haml b/app/views/admin/conference/new.html.haml new file mode 100644 index 00000000..76301c7f --- /dev/null +++ b/app/views/admin/conference/new.html.haml @@ -0,0 +1,13 @@ += semantic_form_for(@conference, :url => admin_conference_index_path) do |f| + = f.inputs "Basic Information" do + = f.input :title, :hint => "The name of your conference as it shall appear throughout the site. Example: 'OpenSUSE Conference 2013'" + = f.input :short_title, :hint => "A short and unique handle for your conference, using only lower-case letters, numbers and underscores. This will be used to identify your conference in URLs etc. Example: 'froscon2011'" + = f.input :social_tag, :hint => "The hashtag you'll use on Twitter and Google+. Don't include the '#' sign!'" + = f.input :contact_email, :hint => "Contact email address for your conference. Will be used as reply-to address in emails sent out by the system." + = f.inputs "Scheduling" do + = f.input :timezone, :as => :time_zone, :hint => "Please select in what time zone your conference will take place. This is needed to correctly display times for your events." + = f.input :start_date, :as => :string, :input_html => { :id => "conference-start-datepicker", :readonly => "readonly" } + = f.input :end_date, :as => :string, :input_html => { :id => "conference-end-datepicker", :readonly => "readonly" } + = f.input :html_export_path, :hint => "The path for static HTML exports" + = f.actions do + = f.action :submit, :button_html => {:class => "btn primary"} diff --git a/app/views/admin/conference/show.html.haml b/app/views/admin/conference/show.html.haml new file mode 100644 index 00000000..4d4df114 --- /dev/null +++ b/app/views/admin/conference/show.html.haml @@ -0,0 +1,17 @@ +.container-fluid + .row-fluid + .span3 + = render 'admin/conference/sidebar', :activated => "Conference" + .span9 + = semantic_form_for(@conference, :url => admin_conference_path(@conference.short_title),:html => {:multipart => true}) do |f| + = f.input :title, :hint => "The full name of the conference, such as 'OpenSUSE Conference 2013'" + = f.input :short_title, :hint => "A short title, such as 'osc2013', to be used in URLs" + = f.input :social_tag, :hint => "The hashtag you'll use on Twitter and Google+. Don't include the '#' sign!'" + = f.input :contact_email, :hint => "Contact email address for your conference. Will be used as reply-to address in emails sent out by the system." + = f.input :timezone, :as => :time_zone, :hint => "The conference time zone" + = f.input :start_date, :as => :string, :input_html => { :id => "conference-start-datepicker", :readonly => "readonly" } + = f.input :end_date, :as => :string, :input_html => { :id => "conference-end-datepicker", :readonly => "readonly" } + = f.input :html_export_path, :hint => "The path for static HTML exports" + = f.input :cfp_open, :label => false, :hint => "Allow people to submit papers?" + = f.input :registration_open, :label => false, :hint => "Allow people to register as attendees?" + = f.action :submit, :as => :button, :button_html => {:class => "btn btn-primary"} \ No newline at end of file diff --git a/app/views/admin/events/_person_fields.html.haml b/app/views/admin/events/_person_fields.html.haml new file mode 100644 index 00000000..4999c2ab --- /dev/null +++ b/app/views/admin/events/_person_fields.html.haml @@ -0,0 +1,6 @@ +.nested-fields + = f.inputs do + = f.input :email + = f.input :public_name + = remove_association_link :person, f + diff --git a/app/views/admin/events/edit.html.haml b/app/views/admin/events/edit.html.haml new file mode 100644 index 00000000..9372b87b --- /dev/null +++ b/app/views/admin/events/edit.html.haml @@ -0,0 +1,2 @@ +.container + = render 'proposal/form' \ No newline at end of file diff --git a/app/views/admin/events/index.html.haml b/app/views/admin/events/index.html.haml new file mode 100644 index 00000000..902f8d43 --- /dev/null +++ b/app/views/admin/events/index.html.haml @@ -0,0 +1,48 @@ +.row-fluid + .span12 + %table.table.table-striped.table-bordered.table-hover + %thead + %th + %b Title + %th + %b Submitter + %th + %b Type + %th + %b State + - @events.each do |event| + %tr + %td + =link_to event.title, admin_conference_event_path(@conference.short_title, event) + %td + - if !event.submitter.nil? + =link_to event.submitter.public_name, admin_person_path(event.submitter) + - else + Unknown submitter + %td + = event.event_type.title + %td + - if event.state == "withdrawn" + Withdrawn + - else + .dropdown + = link_to "#", :class => "dropdown-toggle" do + = event.state.humanize + + %ul.dropdown-menu + - if event.transition_possible? :accept + %li= link_to "Accept event (no email)", update_state_admin_conference_event_path(@conference.short_title, event, :transition => :accept, :send_mail => false), + :method => :put, :hint => "Accept this event without sending an automated email." + - if event.transition_possible? :reject + %li= link_to "Reject event (no email)", update_state_admin_conference_event_path(@conference.short_title, event, :transition => :reject, :send_mail => false), + :method => :put, :confirm => "Are you sure?", + :hint => "Reject this event without sending an automated email." + - if event.transition_possible? :start_review + %li= link_to "Start review", update_state_admin_conference_event_path(@conference.short_title, event, :transition => :start_review), + :method => :put + - if event.transition_possible? :confirm + %li= link_to "Confirm event", update_state_admin_conference_event_path(@conference.short_title, event, :transition => :confirm), + :method => :put, :hint => "Confirm that the speaker(s) will be present and that the event will actually take place." + - if event.transition_possible? :cancel + %li= link_to "Cancel event", update_state_admin_conference_event_path(@conference.short_title, event, :transition => :cancel), + :method => :put, :hint => "Mark this event as cancelled. Usually this means that the speakers had to cancel their appearance." diff --git a/app/views/admin/events/show.html.haml b/app/views/admin/events/show.html.haml new file mode 100644 index 00000000..bdd42183 --- /dev/null +++ b/app/views/admin/events/show.html.haml @@ -0,0 +1,112 @@ +.row-fluid + .span10 + %h3 + = @event.title + %i= @event.subtitle + + .span2 + = link_to "Edit Submission", edit_admin_conference_event_path(@conference.short_title, @event), + :class => "btn btn-mini btn-primary pull-right", :style => "margin-top:20px;" + +.row-fluid + .span12 + %table.table + %tr + %td + %b State + %td + .dropdown + = link_to "#", :class => "dropdown-toggle" do + = @event.state.humanize + + %ul.dropdown-menu + - if @event.transition_possible? :accept + %li= link_to "Accept event (no email)", update_state_admin_conference_event_path(@conference.short_title, @event, :transition => :accept, :send_mail => false), + :method => :put, :hint => "Accept this event without sending an automated email." + - if @event.transition_possible? :reject + %li= link_to "Reject event (no email)", update_state_admin_conference_event_path(@conference.short_title, @event, :transition => :reject, :send_mail => false), + :method => :put, :confirm => "Are you sure?", + :hint => "Reject this event without sending an automated email." + - if @event.transition_possible? :start_review + %li= link_to "Start review", update_state_admin_conference_event_path(@conference.short_title, @event, :transition => :start_review), + :method => :put + - if @event.transition_possible? :confirm + %li= link_to "Confirm event", update_state_admin_conference_event_path(@conference.short_title, @event, :transition => :confirm), + :method => :put, :hint => "Confirm that the speaker(s) will be present and that the event will actually take place." + - if @event.transition_possible? :cancel + %li= link_to "Cancel event", update_state_admin_conference_event_path(@conference.short_title, @event, :transition => :cancel), + :method => :put, :hint => "Mark this event as cancelled. Usually this means that the speakers had to cancel their appearance." + + %tr + %td + %b Submitter + %td + = link_to @event.submitter.public_name, admin_person_path(@conference.short_title, @event.submitter) + ( + = link_to @event.submitter.email, "mailto: #{@event.submitter.email}" + ) + %tr + %td + %b Biography + %td + = simple_format(@event.submitter.biography) + %tr + %td + %b Submitted on + %td= @event.created_at + %tr + %td + %b Last updated on + %td= @event.updated_at + %tr + %td + %b Abstract + %td= simple_format(@event.abstract) + %tr + %td + %b Description + %td= simple_format(@event.description) + - if @event.event_attachments.size > 0 + %table.table + %thead + %th + %b Filename + %th + %b Title + %th + %b Size + %th + %b Public? + %th + %tbody + - @event.event_attachments.each do |a| + %tr + %td + = link_to a.attachment_file_name, conference_proposal_event_attachment_path(@conference.short_title, @event.id, a.id) + %td + = a.title + %td + = number_to_human_size a.attachment_file_size + %td + - if a.public? + Public + - else + Not Public + %td + = link_to "Delete", conference_proposal_event_attachment_path(@conference.short_title, @event.id, a.id), + :method => :delete, :confirm => "Are you sure you want to delete this attachment? It's permanant!" + +.row-fluid + = link_to "Comments (#{@comment_count})", "#", :id => "event-comment-link" + #comments-div + %hr + %ul.media + %div + .row-fluid + = form_tag(comment_admin_conference_event_path(@conference.short_title, @event.id), :method => :post) do + = text_area_tag(:comment, "") + = submit_tag "Add Comment", :class => "btn btn-primary pull-right" + %br + - @comments.each do |comment| + %div + = raw format_comments(comment) \ No newline at end of file diff --git a/app/views/admin/eventtype/_event_type_fields.html.erb b/app/views/admin/eventtype/_event_type_fields.html.erb new file mode 100644 index 00000000..bca9f61b --- /dev/null +++ b/app/views/admin/eventtype/_event_type_fields.html.erb @@ -0,0 +1,7 @@ +
+ <%= f.inputs do %> + <%= f.input :title %> + <%= f.input :length, :input_html => {:size => 3} %> + <%= remove_association_link :event_type, f %> + <% end %> +
diff --git a/app/views/admin/eventtype/event_type_list.html.haml b/app/views/admin/eventtype/event_type_list.html.haml new file mode 100644 index 00000000..d1715ce5 --- /dev/null +++ b/app/views/admin/eventtype/event_type_list.html.haml @@ -0,0 +1,8 @@ +.container-fluid + .row-fluid + .span3 + = render 'admin/conference/sidebar', :activated => "Event Types" + .span9 + = semantic_form_for(@conference, :url => admin_conference_eventtype_update_path(@conference.short_title)) do |f| + = dynamic_association :event_types, "Event Types", f + = f.action :submit, :as => :button, :button_html => {:class => "btn btn-primary"} \ No newline at end of file diff --git a/app/views/admin/people/index.html.haml b/app/views/admin/people/index.html.haml new file mode 100644 index 00000000..af8a64bf --- /dev/null +++ b/app/views/admin/people/index.html.haml @@ -0,0 +1,18 @@ +%table.table.table-striped.table-bordered.table-hover + %thead + %th + %b Last Name + %th + %b First Name + %th + %b Public Name + %th + %b # of Conference Registrations + %th + - @people.each do |person| + %tr + %td= person.last_name + %td= person.first_name + %td= person.public_name + %td= person.registrations.count + %td= link_to "View", admin_person_path(person) \ No newline at end of file diff --git a/app/views/admin/people/show.html.haml b/app/views/admin/people/show.html.haml new file mode 100644 index 00000000..c996aec3 --- /dev/null +++ b/app/views/admin/people/show.html.haml @@ -0,0 +1,49 @@ +%table.table + %tr + %td + %b First Name + %td + = @person.first_name + %tr + %td + %b Last Name + %td + = @person.last_name + %tr + %td + %b Public Name + %td + = @person.public_name + %tr + %td + %b Company + %td + = @person.company + %tr + %td + %b Email + %td + = @person.email + %tr + %td + %b Created At + %td + = @person.created_at + %tr + %td + %b Updated At + %td + = @person.updated_at + %tr + %td + %b Biography + %td + = @person.biography + %tr + %td + %b Registered to attend + %td + - if @person.registrations.count == 0 + None + - else + = @person.registrations.map { |r| r.conference.title }.join ',' \ No newline at end of file diff --git a/app/views/admin/registrations/show.html.haml b/app/views/admin/registrations/show.html.haml new file mode 100644 index 00000000..a3e5d168 --- /dev/null +++ b/app/views/admin/registrations/show.html.haml @@ -0,0 +1,48 @@ +.row-fluid + .span12 + .pull-right{:style=>"margin-top:20px; margin-bottom:20px;"} + = link_to "Export PDF", admin_conference_registrations_path(@conference.short_title, :format => :pdf), :class => "btn btn-success" +.row-fluid + .span12 + %table.table.table-striped.table-bordered.table-hover + %thead + %th + %b Last Name + %th + %b First Name + %th + %b Public Name + %th + %b Email + %th + %b Attending Social Events + %th + %b Attending With Partner + %th + %b Arrival Date + %th + %b Departure Date + %th + %th + - @registrations.each do |registration| + %tr + %td + = registration.last_name + %td + = registration.first_name + %td + = registration.public_name + %td + = registration.email + %td + = registration.attending_social_events + %td + = registration.attending_social_events_with_partner + %td + = registration.arrival + %td + = registration.departure + %td + = link_to "Edit", "#", :class => "btn btn-primary" + %td + = link_to "Delete", "#", :class => "btn btn-danger", :confirm => "Really delete registration for #{registration.public_name}?" \ No newline at end of file diff --git a/app/views/admin/registrations/show.pdf.prawn b/app/views/admin/registrations/show.pdf.prawn new file mode 100644 index 00000000..38a8031a --- /dev/null +++ b/app/views/admin/registrations/show.pdf.prawn @@ -0,0 +1,38 @@ +prawn_document(:force_download=>true, :filename => @pdf_filename) do |pdf| + table_array = [] + header_array = [" ", + "Last Name", + "First Name", + "Public Name", + "Email", + "Attending Social Events", + "Attending With Partner", + "Arrival Date", + "Departure Date"] + table_array << header_array + @registrations.each do |registration| + row = [] + row << "" + row << registration.last_name + row << registration.first_name + row << registration.public_name + row << registration.email + if registration.attending_social_events + row << "X" + else + row << " " + end + + if registration.attending_social_events_with_partner.to_s + row << "X" + else + row << " " + end + row << registration.arrival + row << registration.departure + table_array << row + end + + pdf.text "#{@conference.title} Registrations", :font_size => 25 + pdf.table table_array, :header => true, :cell_style => {:size => 5, :border_width => 1} +end \ No newline at end of file diff --git a/app/views/admin/rooms/_room_fields.html.erb b/app/views/admin/rooms/_room_fields.html.erb new file mode 100644 index 00000000..203176e8 --- /dev/null +++ b/app/views/admin/rooms/_room_fields.html.erb @@ -0,0 +1,8 @@ +
+ <%= f.inputs do %> + <%= f.input :name %> + <%= f.input :size, :input_html => {:size => 5} %> + <%= f.input :public, :as => :boolean %> + <%= remove_association_link :room, f %> + <% end %> +
diff --git a/app/views/admin/rooms/rooms_list.html.haml b/app/views/admin/rooms/rooms_list.html.haml new file mode 100644 index 00000000..76c9b7eb --- /dev/null +++ b/app/views/admin/rooms/rooms_list.html.haml @@ -0,0 +1,8 @@ +.container-fluid + .row-fluid + .span3 + = render 'admin/conference/sidebar', :activated => "Rooms" + .span9 + = semantic_form_for(@conference, :url => admin_conference_rooms_update_path(@conference.short_title)) do |f| + = dynamic_association :rooms, "Rooms", f + = f.action :submit, :as => :button, :button_html => {:class => "btn btn-primary"} \ No newline at end of file diff --git a/app/views/admin/tracks/_track_fields.html.erb b/app/views/admin/tracks/_track_fields.html.erb new file mode 100644 index 00000000..b40c76d8 --- /dev/null +++ b/app/views/admin/tracks/_track_fields.html.erb @@ -0,0 +1,8 @@ +
+ <%= f.inputs do %> + <%= f.input :name %> + <%= f.input :color, :input_html => {:size => 6} %> + <%= f.input :description, :input_html => {:rows => 2 } %> + <%= remove_association_link :track, f %> + <% end %> +
diff --git a/app/views/admin/tracks/tracks_list.html.haml b/app/views/admin/tracks/tracks_list.html.haml new file mode 100644 index 00000000..7ada0212 --- /dev/null +++ b/app/views/admin/tracks/tracks_list.html.haml @@ -0,0 +1,8 @@ +.container-fluid + .row-fluid + .span3 + = render 'admin/conference/sidebar', :activated => "Tracks" + .span9 + = semantic_form_for(@conference, :url => admin_conference_tracks_update_path(@conference.short_title)) do |f| + = dynamic_association :tracks, "Tracks", f + = f.action :submit, :as => :button, :button_html => {:class => "btn btn-primary"} \ No newline at end of file diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml new file mode 100644 index 00000000..bd0d5f64 --- /dev/null +++ b/app/views/admin/users/index.html.haml @@ -0,0 +1,57 @@ +.container-fluid + .row-fluid + .span12 + %table.table.table-striped.table-bordered.table-hover + %thead + %th + %b Email + %th + %b Last Name + %th + %b First Name + %th + %b Public Name + %th + %b Roles + %th + %th + - @users.each do |user| + %tr + %td + = user.email + %td + = user.last_name + %td + = user.first_name + %td + = user.public_name + %td + = user.roles.map { |role| role.name }.join ',' + %td + .modal.hide.fade{:id => "user-role-selection-#{user.id}", "role" => "dialog", "aria-hidden" => "true"} + .modal-header + %button{"type"=>"button", :class=>"close", "data-dismiss"=>"modal", "aria-hidden"=>"true"} + × + %h3{:id => "role-selector-header-#{user.id}"} + Modifying Roles + .modal-body + - if current_user == user + You cannot modify your own role! + %br + %button{:class=> "btn btn-danger", "data-dismiss"=> "modal", "aria-hidden"=>"true"} + Cancel + + - else + = "Give #{user.public_name} (#{user.email}) the following roles:" + = semantic_form_for(user, :url => admin_user_path(user), :method => :put) do |f| + = f.input :roles, :label => false + %button{:class=> "btn btn-danger", "data-dismiss"=> "modal", "aria-hidden"=>"true"} + Cancel + = f.action :submit, :as => :button, :button_html => {:value => "Save", :class => "btn btn-primary"} + =link_to "Modify Roles", "#", "data-toggle" => "modal", "data-target" => "#user-role-selection-#{user.id}}" + %td + =link_to "Details", "#", :class => "user-details-popover", "data-trigger" => "click", "data-placement" => "bottom", + "data-html" => "true", + "data-content" => user.popup_details, + "data-original-title" => "" + diff --git a/app/views/admin/venue/venue_info.html.haml b/app/views/admin/venue/venue_info.html.haml new file mode 100644 index 00000000..a4431b76 --- /dev/null +++ b/app/views/admin/venue/venue_info.html.haml @@ -0,0 +1,11 @@ +.container-fluid + .row-fluid + .span3 + = render 'admin/conference/sidebar', :activated => "Venue" + .span9 + = semantic_form_for(@venue, :url => admin_conference_venue_update_path(@conference.short_title),:html => {:multipart => true}) do |f| + = f.input :name + = f.input :address + = f.input :website + = f.input :description, :input_html => { :rows => 10, :cols => 20 } + = f.action :submit, :as => :button, :button_html => {:class => "btn btn-primary"} \ No newline at end of file diff --git a/app/views/conference_registration/register.html.haml b/app/views/conference_registration/register.html.haml new file mode 100644 index 00000000..3774998b --- /dev/null +++ b/app/views/conference_registration/register.html.haml @@ -0,0 +1,22 @@ +.container-fluid + .row-fluid + .span12 + %h3.pull-left + Registration for + = @conference.title + .row-fluid + .span12 + = semantic_form_for(@registration, :url => register_conference_path(@conference.short_title), :html => { :method => :put }) do |f| + = f.fields_for :person do + = f.inputs :public_name, :for => :person + = f.input :attending_social_events, :label => false + = f.input :attending_social_events_with_partner, :label => false + = f.input :using_affiliated_lodging, :label => false + = f.input :arrival, :as => :string, :input_html => { :id => "conference-start-datepicker", :readonly => "readonly" } + = f.input :departure, :as => :string, :input_html => { :id => "conference-end-datepicker", :readonly => "readonly" } + - if @registered + = f.action :submit, :button_html => { :value => "Update Registration", :class => "btn btn-primary" } + = link_to "Unregister", register_conference_path(@conference.short_title),:method => :delete, :class => "btn btn-danger", + :confirm => "Are you sure you want to unregister?" + - else + = f.action :submit, :button_html => { :value => "Register", :class => "btn btn-primary" } diff --git a/app/views/devise/confirmations/new.html.erb b/app/views/devise/confirmations/new.html.erb new file mode 100644 index 00000000..81e4472d --- /dev/null +++ b/app/views/devise/confirmations/new.html.erb @@ -0,0 +1,12 @@ +

Resend confirmation instructions

+ +<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %> + <%= devise_error_messages! %> + +
<%= f.label :email %>
+ <%= f.email_field :email %>
+ +
<%= f.submit "Resend confirmation instructions" %>
+<% end %> + +<%= render "devise/shared/links" %> diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb new file mode 100644 index 00000000..a5c4585e --- /dev/null +++ b/app/views/devise/mailer/confirmation_instructions.html.erb @@ -0,0 +1,5 @@ +

Welcome <%= @resource.email %>!

+ +

You can confirm your account email through the link below:

+ +

<%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %>

diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb new file mode 100644 index 00000000..ae9e888a --- /dev/null +++ b/app/views/devise/mailer/reset_password_instructions.html.erb @@ -0,0 +1,8 @@ +

Hello <%= @resource.email %>!

+ +

Someone has requested a link to change your password, and you can do this through the link below.

+ +

<%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %>

+ +

If you didn't request this, please ignore this email.

+

Your password won't change until you access the link above and create a new one.

diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb new file mode 100644 index 00000000..2263c219 --- /dev/null +++ b/app/views/devise/mailer/unlock_instructions.html.erb @@ -0,0 +1,7 @@ +

Hello <%= @resource.email %>!

+ +

Your account has been locked due to an excessive amount of unsuccessful sign in attempts.

+ +

Click the link below to unlock your account:

+ +

<%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %>

diff --git a/app/views/devise/passwords/edit.html.erb b/app/views/devise/passwords/edit.html.erb new file mode 100644 index 00000000..fe620ef4 --- /dev/null +++ b/app/views/devise/passwords/edit.html.erb @@ -0,0 +1,16 @@ +

Change your password

+ +<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %> + <%= devise_error_messages! %> + <%= f.hidden_field :reset_password_token %> + +
<%= f.label :password, "New password" %>
+ <%= f.password_field :password %>
+ +
<%= f.label :password_confirmation, "Confirm new password" %>
+ <%= f.password_field :password_confirmation %>
+ +
<%= f.submit "Change my password" %>
+<% end %> + +<%= render "devise/shared/links" %> diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb new file mode 100644 index 00000000..23501646 --- /dev/null +++ b/app/views/devise/passwords/new.html.erb @@ -0,0 +1,12 @@ +

Forgot your password?

+ +<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| %> + <%= devise_error_messages! %> + +
<%= f.label :email %>
+ <%= f.email_field :email %>
+ +
<%= f.submit "Send me reset password instructions" %>
+<% end %> + +<%= render "devise/shared/links" %> diff --git a/app/views/devise/registrations/_edit_account.html.erb b/app/views/devise/registrations/_edit_account.html.erb new file mode 100644 index 00000000..1945f846 --- /dev/null +++ b/app/views/devise/registrations/_edit_account.html.erb @@ -0,0 +1,21 @@ +<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %> +
<%= f.label :email %>
+ <%= f.email_field :email %>
+ +
<%= f.label :password %> (leave blank if you don't want to change it)
+ <%= f.password_field :password, :autocomplete => "off" %>
+ +
<%= f.label :password_confirmation %>
+ <%= f.password_field :password_confirmation %>
+ +
<%= f.label :current_password %> (we need your current password to confirm your changes)
+ <%= f.password_field :current_password %>
+ +
<%= f.submit "Update" %>
+<% end %> + +

Cancel my account

+ +

Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :data => { :confirm => "Are you sure?" }, :method => :delete %>.

+ +<%= link_to "Back", :back %> diff --git a/app/views/devise/registrations/_edit_profile.html.erb b/app/views/devise/registrations/_edit_profile.html.erb new file mode 100644 index 00000000..9ea5b36a --- /dev/null +++ b/app/views/devise/registrations/_edit_profile.html.erb @@ -0,0 +1,20 @@ +<% if false %> +<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %> + <%= f.fields_for :person do |p| %> +

<%= p.label :first_name %>

+

<%= p.text_field :first_name %>

+ +

<%= p.label :last_name %>

+

<%= p.text_field :last_name %>

+ <% end %> +
<%= f.submit "Update" %>
+<% end %> + +<% end %> + +<%= semantic_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %> + <%= f.fields_for :person do |p| %> + <%= f.inputs :first_name, :last_name, :for => :person %> + <% end %> +
<%= f.submit "Update" %>
+<% end %> diff --git a/app/views/devise/registrations/edit.html.erb-backup b/app/views/devise/registrations/edit.html.erb-backup new file mode 100644 index 00000000..0abfb3fc --- /dev/null +++ b/app/views/devise/registrations/edit.html.erb-backup @@ -0,0 +1,18 @@ +<%= devise_error_messages! %> +<%= semantic_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %> + + <%= f.inputs :name => "Profile" do %> + <%= f.fields_for :person do |p| %> + <%= f.inputs :first_name, :last_name, :for => :person %> + <% end %> + <% end %> + + <%= f.inputs :name => "Account" do %> + <%= f.input :email %> + <%= f.input :password, :hint => "(Leave blank if you don't want to change it)", :input_html => {:autocomplete => "off"} %> + <%= f.input :password_confirmation, :input_html => {:autocomplete => "off"} %> + <%= f.input :current_password, :input_html => {:autocomplete => "off"}, :hint => "(we need your current password to confirm your changes)" %> + <% end %> + +
<%= f.submit "Update" %>
+<% end %> diff --git a/app/views/devise/registrations/edit.html.haml b/app/views/devise/registrations/edit.html.haml new file mode 100644 index 00000000..5a88d768 --- /dev/null +++ b/app/views/devise/registrations/edit.html.haml @@ -0,0 +1,19 @@ +.container + .row-fluid + = semantic_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| + = f.inputs :name => "Profile" do + = f.fields_for :person do |p| + = p.inputs :first_name, :last_name, :public_name + = p.input :company, :label => "Affiliation", :hint => "This could be a company, a user group, or nothing at all." + = p.input :biography, :input_html => {:rows => 5, "onkeyup" => "word_count(this, 'biography-count')"}, :for => :person + You have used + %span#biography-count #{current_user.person.biography_word_count} + words. Biographies are limited to 150 words. + %br + %br + = f.inputs :name => "Account" do + = f.input :email, :required => false + = f.input :password, :hint => "(Leave blank if you don't want to change it)", :input_html => {:autocomplete => "off"} + = f.input :password_confirmation, :input_html => {:autocomplete => "off"} + = f.input :current_password, :input_html => {:autocomplete => "off"}, :hint => "(we need your current password to confirm password or email changes)" + = f.submit "Update" diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb new file mode 100644 index 00000000..9703db37 --- /dev/null +++ b/app/views/devise/registrations/new.html.erb @@ -0,0 +1,18 @@ +

Sign up

+ +<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %> + <%= devise_error_messages! %> + +
<%= f.label :email %>
+ <%= f.email_field :email %>
+ +
<%= f.label :password %>
+ <%= f.password_field :password %>
+ +
<%= f.label :password_confirmation %>
+ <%= f.password_field :password_confirmation %>
+ +
<%= f.submit "Sign up" %>
+<% end %> + +<%= render "devise/shared/links" %> diff --git a/app/views/devise/sessions/new.html.erb-backup b/app/views/devise/sessions/new.html.erb-backup new file mode 100644 index 00000000..30ab9196 --- /dev/null +++ b/app/views/devise/sessions/new.html.erb-backup @@ -0,0 +1,18 @@ +/ +

Sign in

+ +<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %> +
<%= f.label :email %>
+ <%= f.email_field :email %>
+ +
<%= f.label :password %>
+ <%= f.password_field :password %>
+ + <% if devise_mapping.rememberable? -%> +
<%= f.check_box :remember_me %> <%= f.label :remember_me %>
+ <% end -%> + +
<%= f.submit "Sign in" %>
+<% end %> + +<%= render "devise/shared/links" %> diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml new file mode 100644 index 00000000..0974e5ed --- /dev/null +++ b/app/views/devise/sessions/new.html.haml @@ -0,0 +1,13 @@ +.container + %h2.center-text + Sign in + .row + .span6.offset3 + = semantic_form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| + = f.input :email + = f.input :password + - if devise_mapping.rememberable? + = f.input :remember_me, :as=> :boolean + = f.submit "Sign in" + + = render "devise/shared/links" diff --git a/app/views/devise/shared/_links.erb b/app/views/devise/shared/_links.erb new file mode 100644 index 00000000..eab783a4 --- /dev/null +++ b/app/views/devise/shared/_links.erb @@ -0,0 +1,25 @@ +<%- if controller_name != 'sessions' %> + <%= link_to "Sign in", new_session_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.registerable? && controller_name != 'registrations' %> + <%= link_to "Sign up", new_registration_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.recoverable? && controller_name != 'passwords' %> + <%= link_to "Forgot your password?", new_password_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> + <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> + <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.omniauthable? %> + <%- resource_class.omniauth_providers.each do |provider| %> + <%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %>
+ <% end -%> +<% end -%> \ No newline at end of file diff --git a/app/views/devise/unlocks/new.html.erb b/app/views/devise/unlocks/new.html.erb new file mode 100644 index 00000000..e55e82ee --- /dev/null +++ b/app/views/devise/unlocks/new.html.erb @@ -0,0 +1,12 @@ +

Resend unlock instructions

+ +<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %> + <%= devise_error_messages! %> + +
<%= f.label :email %>
+ <%= f.email_field :email %>
+ +
<%= f.submit "Resend unlock instructions" %>
+<% end %> + +<%= render "devise/shared/links" %> diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml new file mode 100644 index 00000000..92a2bfda --- /dev/null +++ b/app/views/home/index.html.haml @@ -0,0 +1,38 @@ +.container-fluid + %h1.center-text + Upcoming Conferences + - @conferences.each do |conference| + - if conference.cfp_open? + .well + %h2.center-text + = conference.title + %h4.center-text + = conference.date_range_string + .center-text + %i + %a= link_to conference.venue.name, conference.venue.website + , + = conference.venue.address + .row-fluid{:style => "padding-top: 30px;"} + .span4 + - if conference.user_registered?(current_user) + = link_to "Modify Registration", register_conference_path(conference.short_title), :class => "mainbutton center-text" + %br + %i.icon-thumbs-up You're attending! + - else + = link_to "Register", register_conference_path(conference.short_title), :class => "mainbutton center-text" + %br + - if !current_user.nil? + %i.icon-thumbs-down + You haven't registered yet! + .span4.offset4.pull-right + - if !current_user.nil? && current_user.person.proposal_count(conference) > 0 + = link_to "View My Proposals", conference_proposal_index_path(conference.short_title), :class => "mainbutton center-text" + %br + - if !current_user.nil? + %i.icon-star + You've submitted + %b= current_user.person.proposal_count conference + proposals! + - else + = link_to "Submit Proposal", conference_proposal_index_path(conference.short_title), :class => "mainbutton center-text" \ No newline at end of file diff --git a/app/views/layouts/_admin_navigation.html.haml b/app/views/layouts/_admin_navigation.html.haml new file mode 100644 index 00000000..418443f3 --- /dev/null +++ b/app/views/layouts/_admin_navigation.html.haml @@ -0,0 +1,44 @@ +- if @conference.nil? || @conference.short_title.nil? + = link_to "OSEM", admin_conference_index_path, :class => 'brand' +- else + = link_to @conference.title, admin_conference_path(@conference.short_title), :class => 'brand' +- if @conference && !@conference.short_title.nil? + %ul.nav + - if current_page?(admin_conference_registrations_path(@conference.short_title)) + %li.active + = link_to "Registrations", "#" + - else + %li + = link_to "Registrations", admin_conference_registrations_path(@conference.short_title) + - if current_page?(admin_conference_events_path(@conference.short_title)) + %li.active + = link_to "Events", "#" + - else + %li + = link_to "Events", admin_conference_events_path(@conference.short_title) +%ul.nav.secondary-nav.pull-right + - if !@conference.nil? + %li.dropdown + = link_to "#", :class => "dropdown-toggle" do + Export + + %ul.dropdown-menu + %li= link_to "JSON", "#" + %li= link_to "HTML", "#" + %li.dropdown + - unless Conference.count == 1 && !has_role?(current_user, "admin") + = link_to "#", :class => "dropdown-toggle" do + Conferences + + %ul.dropdown-menu + - conferences = Conference.order("created_at DESC") + - unless conferences.nil? + - conferences.each do |c| + - unless @conference == c + %li= link_to c.short_title, admin_conference_path(c.short_title) + - if has_role?(current_user, "admin") + %li= link_to "New Conference", new_admin_conference_path + - if has_role?(current_user, "admin") + %li= link_to "Users", admin_users_path + %li= link_to "People", admin_people_path + %li= link_to "Log out", destroy_user_session_path, :method => :delete \ No newline at end of file diff --git a/app/views/layouts/_messages.html.haml b/app/views/layouts/_messages.html.haml new file mode 100644 index 00000000..fd8e69a8 --- /dev/null +++ b/app/views/layouts/_messages.html.haml @@ -0,0 +1,5 @@ +- flash.each do |name, msg| + - if msg.is_a?(String) + %div{:class => "alert alert-#{name == :notice ? "success" : "error"}"} + %a.close{"data-dismiss" => "alert"} × + = content_tag :div, msg, :id => "flash_#{name}" \ No newline at end of file diff --git a/app/views/layouts/_navigation.html.haml b/app/views/layouts/_navigation.html.haml new file mode 100644 index 00000000..2beda77d --- /dev/null +++ b/app/views/layouts/_navigation.html.haml @@ -0,0 +1,11 @@ += link_to "OSEM", root_path, :class => 'brand' +%ul.nav.pull-right + - if user_signed_in? + %li + = link_to('Logout', destroy_user_session_path, :method=>'delete') + - else + %li + = link_to('Login', new_user_session_path) + - if user_signed_in? + %li + = link_to('Edit account', edit_user_registration_path) diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml new file mode 100644 index 00000000..a36217bb --- /dev/null +++ b/app/views/layouts/admin.html.haml @@ -0,0 +1,27 @@ +!!! +%html + %head + %meta{:charset => "utf-8"} + %meta{:name => "viewport", :content => "width=device-width, initial-scale=1, maximum-scale=1"} + %title= content_for?(:title) ? yield(:title) : "Admin" + %meta{:content => "", :name => "description"} + %meta{:content => "", :name => "author"} + = stylesheet_link_tag "application", :media => "all" + = javascript_include_tag "application" + = csrf_meta_tags + = yield(:head) + %body + .navbar.navbar-fixed-top + .navbar-inner + .container-fluid + = render 'layouts/admin_navigation' + .container + .content + #wrap + #inner-content + .row-fluid + .span12 + = render 'layouts/messages' + .row-fluid + .span12 + = yield \ No newline at end of file diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml new file mode 100644 index 00000000..a68290bc --- /dev/null +++ b/app/views/layouts/application.html.haml @@ -0,0 +1,35 @@ +!!! +%html + %head + %meta{:charset => "utf-8"} + %meta{:name => "viewport", :content => "width=device-width, initial-scale=1, maximum-scale=1"} + %title= content_for?(:title) ? yield(:title) : "OSEM" + %meta{:content => "", :name => "description"} + %meta{:content => "", :name => "author"} + = stylesheet_link_tag "application", :media => "all" + = javascript_include_tag "application" + = csrf_meta_tags + = yield(:head) + %body + .navbar.navbar-fixed-top + .navbar-inner + .container-fluid + = render 'layouts/navigation' + .container + .content + #wrap + #inner-content + .row-fluid + .span12 + = render 'layouts/messages' + .row-fluid + .span12 + = yield + #push + #footer + .container + %p.muted.credit.center-text{:style => "font-size: 10px;"} + OSEM is (C) 2013 + = link_to "Matt Barringer", "http://incoherent.de" + and released under the GPL. You can get the source code from + = link_to "Github.", "https://github.com/mbarringer/osem" \ No newline at end of file diff --git a/app/views/proposal/_form.html.haml b/app/views/proposal/_form.html.haml new file mode 100644 index 00000000..adb5677a --- /dev/null +++ b/app/views/proposal/_form.html.haml @@ -0,0 +1,142 @@ +.tabbable + %ul.nav.nav-tabs + %li.active + = link_to "Proposal", "#proposal-content", "data-toggle"=>"tab" + %li + = link_to "Attachments", "#attachment-content", "data-toggle"=>"tab" + .tab-content + #proposal-content.tab-pane.active + .span12 + = semantic_form_for(@event, :url => @url) do |f| + %section#basic + = f.inputs :name => "Basic Information" do + = f.input :title, :required => true + = f.input :subtitle + = f.input :abstract, :input_html => {:rows => 5, "onkeyup" => "word_count(this, 'abstract-count')"}, :required => true + You have used + %span#abstract-count #{@event.abstract_word_count} + words. Abstracts are limited to 250 words. + %br + %br + = f.input :description, :input_html => {:rows => 5}, :hint => "This will only be shown to organizers, not to attendees." + %section#details + = f.inputs :name => "Event Details" do + = f.input :event_type_id,:as => :select, :collection => @event_types, :include_blank => false + %section#information + = f.inputs :name => "Your Information" do + = semantic_fields_for @person do |p| + = p.input :public_name, :required => true + = p.input :company, :label => "Affiliation", :hint => "This could be a company, a user group, or nothing at all." + = p.input :biography, :required => true, :input_html => {:rows => 5, "onkeyup" => "word_count(this, 'biography-count')"} + You have used + %span#biography-count #{@person.biography_word_count} + words. Biographies are limited to 150 words. + %br + %br + + %section#speakers + = f.inputs :name => "Additional Speakers" do + Will there be any additional speakers? If so, please enter their full names, email address, and a short + biography for each. + = f.input :proposal_additional_speakers, :input_html => {:rows => 5}, :label => false + = f.action :submit, :as => :button, :button_html => {:class => "btn btn-primary"} + #attachment-content.tab-pane + .span12 + = form_for EventAttachment.new, :url => conference_proposal_event_attachment_index_path(@conference.short_title, @event), + :html => { :multipart => true, :id => "fileupload" } do |f| + %table.table.table-striped + %thead + %th + %th + %b Filename + %th + %b Title + %th + %b Size + %th + %b Public + %th + %tbody.files + .row-fluid.fileupload-buttonbar + .btn.btn-success.fileinput-button + %i.icon-plus.icon-white + Add files... + = f.file_field :attachment + = f.hidden_field :event_id, :value => @event.id + +:javascript + $(document).ready( function() { + $('#fileupload').fileupload(); + $('#fileupload').bind('fileuploadsubmit', function (e, data) { + var inputs = data.context.find(':input'); + if (inputs.filter('[required][value=""]').first().focus().length) { + return false; + } + data.formData = inputs.serializeArray(); + }); + + } ); + +:plain + + + diff --git a/app/views/proposal/edit.html.haml b/app/views/proposal/edit.html.haml new file mode 100644 index 00000000..42ae2e85 --- /dev/null +++ b/app/views/proposal/edit.html.haml @@ -0,0 +1,2 @@ +.container + = render 'form' \ No newline at end of file diff --git a/app/views/proposal/index.html.haml b/app/views/proposal/index.html.haml new file mode 100644 index 00000000..9296f0ef --- /dev/null +++ b/app/views/proposal/index.html.haml @@ -0,0 +1,18 @@ +.container-fluid + .row-fluid + .span13 + %h2.pull-left + My Proposals + .pull-right{:style=>"margin-top:20px;"} + = link_to "New Proposal", new_conference_proposal_path(@conference.short_title), :class => "btn btn-primary" + - @events.each do |event| + .row-fluid + .span12 + .well + .row-fluid + .span10 + = event.title + .pull-right + = link_to "Edit", edit_conference_proposal_path(@conference.short_title, event.id), :class => "btn btn-mini btn-primary" + = link_to "Withdraw", conference_proposal_path(@conference.short_title, event.id), :method => :delete, + :confirm => "Are you sure you want to withdraw this proposal?", :class => "btn btn-mini btn-danger" diff --git a/app/views/proposal/new.html.haml b/app/views/proposal/new.html.haml new file mode 100644 index 00000000..42ae2e85 --- /dev/null +++ b/app/views/proposal/new.html.haml @@ -0,0 +1,2 @@ +.container + = render 'form' \ No newline at end of file diff --git a/app/views/shared/_dynamic_association.html.haml b/app/views/shared/_dynamic_association.html.haml new file mode 100644 index 00000000..1484100a --- /dev/null +++ b/app/views/shared/_dynamic_association.html.haml @@ -0,0 +1,10 @@ += f.inputs title do + - if hint + %p.inline-hint= hint + %div{:class => association_name.to_s} + = f.semantic_fields_for association_name do |association_form| + = render association_name.to_s.singularize + "_fields", :f => association_form + .links + = add_association_link association_name, f, association_name + %br + %br diff --git a/config.ru b/config.ru new file mode 100644 index 00000000..988dac89 --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +# This file is used by Rack-based servers to start the application. + +require ::File.expand_path('../config/environment', __FILE__) +run Osem::Application diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 00000000..76448fbb --- /dev/null +++ b/config/application.rb @@ -0,0 +1,63 @@ +require File.expand_path('../boot', __FILE__) + +require 'rails/all' +include ActionView::Helpers::NumberHelper + +if defined?(Bundler) + # If you precompile assets before deploying to production, use this line + Bundler.require(*Rails.groups(:assets => %w(development test))) + # If you want your assets lazily compiled in production, use this line + # Bundler.require(:default, :assets, Rails.env) +end + +module Osem + class Application < Rails::Application + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers + # -- all .rb files in that directory are automatically loaded. + + # Custom directories with classes and modules you want to be autoloadable. + # config.autoload_paths += %W(#{config.root}/extras) + + # Only load the plugins named here, in the order given (default is alphabetical). + # :all can be used as a placeholder for all plugins not explicitly named. + # config.plugins = [ :exception_notification, :ssl_requirement, :all ] + + # Activate observers that should always be running. + # config.active_record.observers = :cacher, :garbage_collector, :forum_observer + + # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. + # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. + # config.time_zone = 'Central Time (US & Canada)' + + # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. + # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] + # config.i18n.default_locale = :de + + # Configure the default encoding used in templates for Ruby 1.9. + config.encoding = "utf-8" + + # Configure sensitive parameters which will be filtered from the log file. + config.filter_parameters += [:password] + + # Enable escaping HTML in JSON. + config.active_support.escape_html_entities_in_json = true + + # Use SQL instead of Active Record's schema dumper when creating the database. + # This is necessary if your schema can't be completely dumped by the schema dumper, + # like if you have constraints or database-specific column types + # config.active_record.schema_format = :sql + + # Enforce whitelist mode for mass assignment. + # This will create an empty whitelist of attributes available for mass-assignment for all models + # in your app. As such, your models will need to explicitly whitelist or blacklist accessible + # parameters by using an attr_accessible or attr_protected declaration. + config.active_record.whitelist_attributes = true + + # Enable the asset pipeline + config.assets.enabled = true + + # Version of your assets, change this if you want to expire all your assets + config.assets.version = '1.0' + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 00000000..4489e586 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,6 @@ +require 'rubygems' + +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) + +require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 00000000..51a4dd45 --- /dev/null +++ b/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.sqlite3 + pool: 5 + timeout: 5000 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: sqlite3 + database: db/test.sqlite3 + pool: 5 + timeout: 5000 + +production: + adapter: sqlite3 + database: db/production.sqlite3 + pool: 5 + timeout: 5000 diff --git a/config/deploy.rb b/config/deploy.rb new file mode 100644 index 00000000..f3f702f9 --- /dev/null +++ b/config/deploy.rb @@ -0,0 +1,16 @@ +namespace :paperclip do + + desc "Create a storage folder for Paperclip attachment in shared path" + task :create_storage do + run "mkdir -p #{shared_path}/storage" + end + + desc "Link the Paperclip storage folder into the current release" + task :link_storage do + run "ln -nfs #{shared_path}/storage #{release_path}/storage" + end + +end + +before "deploy:setup", 'paperclip:create_storage' +after "deploy:update_code", "paperclip:link_storage" diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 00000000..d5b37271 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,5 @@ +# Load the rails application +require File.expand_path('../application', __FILE__) + +# Initialize the rails application +Osem::Application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 00000000..113e6099 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,39 @@ +Osem::Application.configure do + # Settings specified here will take precedence over those in config/application.rb + + # In the development environment your application's code is reloaded on + # every request. This slows down response time but is perfect for development + # since you don't have to restart the web server when you make code changes. + config.cache_classes = false + + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true + + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Don't care if the mailer can't send + config.action_mailer.raise_delivery_errors = false + + # Print deprecation notices to the Rails logger + config.active_support.deprecation = :log + + # Only use best-standards-support built into browsers + config.action_dispatch.best_standards_support = :builtin + + # Raise exception on mass assignment protection for Active Record models + config.active_record.mass_assignment_sanitizer = :strict + + # Log the query plan for queries taking more than this (works + # with SQLite, MySQL, and PostgreSQL) + config.active_record.auto_explain_threshold_in_seconds = 0.5 + + # Do not compress assets + config.assets.compress = false + config.assets.compile = false + + # Expands the lines which load the assets + config.assets.debug = true + config.action_mailer.default_url_options = { :host => 'localhost:3000' } +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 00000000..e5a60292 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,67 @@ +Osem::Application.configure do + # Settings specified here will take precedence over those in config/application.rb + + # Code is not reloaded between requests + config.cache_classes = true + + # Full error reports are disabled and caching is turned on + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Disable Rails's static asset server (Apache or nginx will already do this) + config.serve_static_assets = false + + # Compress JavaScripts and CSS + config.assets.compress = true + + # Don't fallback to assets pipeline if a precompiled asset is missed + config.assets.compile = false + + # Generate digests for assets URLs + config.assets.digest = true + + # Defaults to nil and saved in location specified by config.assets.prefix + # config.assets.manifest = YOUR_PATH + + # Specifies the header that your server uses for sending files + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # See everything in the log (default is :info) + # config.log_level = :debug + + # Prepend all log lines with the following tags + # config.log_tags = [ :subdomain, :uuid ] + + # Use a different logger for distributed setups + # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) + + # Use a different cache store in production + # config.cache_store = :mem_cache_store + + # Enable serving of images, stylesheets, and JavaScripts from an asset server + # config.action_controller.asset_host = "http://assets.example.com" + + # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) + # config.assets.precompile += %w( search.js ) + + # Disable delivery errors, bad email addresses will be ignored + # config.action_mailer.raise_delivery_errors = false + + # Enable threaded mode + # config.threadsafe! + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation can not be found) + config.i18n.fallbacks = true + + # Send deprecation notices to registered listeners + config.active_support.deprecation = :notify + + # Log the query plan for queries taking more than this (works + # with SQLite, MySQL, and PostgreSQL) + # config.active_record.auto_explain_threshold_in_seconds = 0.5 +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 00000000..29febc63 --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,37 @@ +Osem::Application.configure do + # Settings specified here will take precedence over those in config/application.rb + + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true + + # Configure static asset server for tests with Cache-Control for performance + config.serve_static_assets = true + config.static_cache_control = "public, max-age=3600" + + # Log error messages when you accidentally call methods on nil + config.whiny_nils = true + + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Raise exceptions instead of rendering exception templates + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment + config.action_controller.allow_forgery_protection = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Raise exception on mass assignment protection for Active Record models + config.active_record.mass_assignment_sanitizer = :strict + + # Print deprecation notices to the stderr + config.active_support.deprecation = :stderr +end diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb new file mode 100644 index 00000000..59385cdf --- /dev/null +++ b/config/initializers/backtrace_silencers.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } + +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb new file mode 100644 index 00000000..d8114c2b --- /dev/null +++ b/config/initializers/devise.rb @@ -0,0 +1,232 @@ +# Use this hook to configure devise mailer, warden hooks and so forth. +# Many of these configuration options can be set straight in your model. +Devise.setup do |config| + # ==> Mailer Configuration + # Configure the e-mail address which will be shown in Devise::Mailer, + # note that it will be overwritten if you use your own mailer class with default "from" parameter. + config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com" + + # Configure the class responsible to send e-mails. + # config.mailer = "Devise::Mailer" + + # ==> ORM configuration + # Load and configure the ORM. Supports :active_record (default) and + # :mongoid (bson_ext recommended) by default. Other ORMs may be + # available as additional gems. + require 'devise/orm/active_record' + + # ==> Configuration for any authentication mechanism + # Configure which keys are used when authenticating a user. The default is + # just :email. You can configure it to use [:username, :subdomain], so for + # authenticating a user, both parameters are required. Remember that those + # parameters are used only when authenticating and not when retrieving from + # session. If you need permissions, you should implement that in a before filter. + # You can also supply a hash where the value is a boolean determining whether + # or not authentication should be aborted when the value is not present. + # config.authentication_keys = [ :email ] + + # Configure parameters from the request object used for authentication. Each entry + # given should be a request method and it will automatically be passed to the + # find_for_authentication method and considered in your model lookup. For instance, + # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. + # The same considerations mentioned for authentication_keys also apply to request_keys. + # config.request_keys = [] + + # Configure which authentication keys should be case-insensitive. + # These keys will be downcased upon creating or modifying a user and when used + # to authenticate or find a user. Default is :email. + config.case_insensitive_keys = [ :email ] + + # Configure which authentication keys should have whitespace stripped. + # These keys will have whitespace before and after removed upon creating or + # modifying a user and when used to authenticate or find a user. Default is :email. + config.strip_whitespace_keys = [ :email ] + + # Tell if authentication through request.params is enabled. True by default. + # It can be set to an array that will enable params authentication only for the + # given strategies, for example, `config.params_authenticatable = [:database]` will + # enable it only for database (email + password) authentication. + # config.params_authenticatable = true + + # Tell if authentication through HTTP Basic Auth is enabled. False by default. + # It can be set to an array that will enable http authentication only for the + # given strategies, for example, `config.http_authenticatable = [:token]` will + # enable it only for token authentication. + # config.http_authenticatable = false + + # If http headers should be returned for AJAX requests. True by default. + # config.http_authenticatable_on_xhr = true + + # The realm used in Http Basic Authentication. "Application" by default. + # config.http_authentication_realm = "Application" + + # It will change confirmation, password recovery and other workflows + # to behave the same regardless if the e-mail provided was right or wrong. + # Does not affect registerable. + # config.paranoid = true + + # By default Devise will store the user in session. You can skip storage for + # :http_auth and :token_auth by adding those symbols to the array below. + # Notice that if you are skipping storage for all authentication paths, you + # may want to disable generating routes to Devise's sessions controller by + # passing :skip => :sessions to `devise_for` in your config/routes.rb + config.skip_session_storage = [:http_auth] + + # ==> Configuration for :database_authenticatable + # For bcrypt, this is the cost for hashing the password and defaults to 10. If + # using other encryptors, it sets how many times you want the password re-encrypted. + # + # Limiting the stretches to just one in testing will increase the performance of + # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use + # a value less than 10 in other environments. + config.stretches = Rails.env.test? ? 1 : 10 + + # Setup a pepper to generate the encrypted password. + # config.pepper = "9a89de1df41b08b48af904bbbc5b8d713addd9d14e2758f12dd14105acd8627fececa02f33f89c0e9764e74262d8874c4a52534b788f5aa4b1716522ae6888b1" + + # ==> Configuration for :confirmable + # A period that the user is allowed to access the website even without + # confirming his account. For instance, if set to 2.days, the user will be + # able to access the website for two days without confirming his account, + # access will be blocked just in the third day. Default is 0.days, meaning + # the user cannot access the website without confirming his account. + # config.allow_unconfirmed_access_for = 2.days + + # If true, requires any email changes to be confirmed (exactly the same way as + # initial account confirmation) to be applied. Requires additional unconfirmed_email + # db field (see migrations). Until confirmed new email is stored in + # unconfirmed email column, and copied to email column on successful confirmation. + config.reconfirmable = true + + # Defines which key will be used when confirming an account + # config.confirmation_keys = [ :email ] + + # ==> Configuration for :rememberable + # The time the user will be remembered without asking for credentials again. + # config.remember_for = 2.weeks + + # If true, extends the user's remember period when remembered via cookie. + # config.extend_remember_period = false + + # Options to be passed to the created cookie. For instance, you can set + # :secure => true in order to force SSL only cookies. + # config.rememberable_options = {} + + # ==> Configuration for :validatable + # Range for password length. Default is 6..128. + # config.password_length = 6..128 + + # Email regex used to validate email formats. It simply asserts that + # an one (and only one) @ exists in the given string. This is mainly + # to give user feedback and not to assert the e-mail validity. + # config.email_regexp = /\A[^@]+@[^@]+\z/ + + # ==> Configuration for :timeoutable + # The time you want to timeout the user session without activity. After this + # time the user will be asked for credentials again. Default is 30 minutes. + # config.timeout_in = 30.minutes + + # If true, expires auth token on session timeout. + # config.expire_auth_token_on_timeout = false + + # ==> Configuration for :lockable + # Defines which strategy will be used to lock an account. + # :failed_attempts = Locks an account after a number of failed attempts to sign in. + # :none = No lock strategy. You should handle locking by yourself. + # config.lock_strategy = :failed_attempts + + # Defines which key will be used when locking and unlocking an account + # config.unlock_keys = [ :email ] + + # Defines which strategy will be used to unlock an account. + # :email = Sends an unlock link to the user email + # :time = Re-enables login after a certain amount of time (see :unlock_in below) + # :both = Enables both strategies + # :none = No unlock strategy. You should handle unlocking by yourself. + # config.unlock_strategy = :both + + # Number of authentication tries before locking an account if lock_strategy + # is failed attempts. + # config.maximum_attempts = 20 + + # Time interval to unlock the account if :time is enabled as unlock_strategy. + # config.unlock_in = 1.hour + + # ==> Configuration for :recoverable + # + # Defines which key will be used when recovering the password for an account + # config.reset_password_keys = [ :email ] + + # Time interval you can reset your password with a reset password key. + # Don't put a too small interval or your users won't have the time to + # change their passwords. + config.reset_password_within = 6.hours + + # ==> Configuration for :encryptable + # Allow you to use another encryption algorithm besides bcrypt (default). You can use + # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1, + # :authlogic_sha512 (then you should set stretches above to 20 for default behavior) + # and :restful_authentication_sha1 (then you should set stretches to 10, and copy + # REST_AUTH_SITE_KEY to pepper) + # config.encryptor = :sha512 + + # ==> Configuration for :token_authenticatable + # Defines name of the authentication token params key + # config.token_authentication_key = :auth_token + + # ==> Scopes configuration + # Turn scoped views on. Before rendering "sessions/new", it will first check for + # "users/sessions/new". It's turned off by default because it's slower if you + # are using only default views. + # config.scoped_views = false + + # Configure the default scope given to Warden. By default it's the first + # devise role declared in your routes (usually :user). + # config.default_scope = :user + + # Set this configuration to false if you want /users/sign_out to sign out + # only the current scope. By default, Devise signs out all scopes. + # config.sign_out_all_scopes = true + + # ==> Navigation configuration + # Lists the formats that should be treated as navigational. Formats like + # :html, should redirect to the sign in page when the user does not have + # access, but formats like :xml or :json, should return 401. + # + # If you have any extra navigational formats, like :iphone or :mobile, you + # should add them to the navigational formats lists. + # + # The "*/*" below is required to match Internet Explorer requests. + # config.navigational_formats = ["*/*", :html] + + # The default HTTP method used to sign out a resource. Default is :delete. + config.sign_out_via = :delete + + # ==> OmniAuth + # Add a new OmniAuth provider. Check the wiki for more information on setting + # up on your models and hooks. + # config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo' + + # ==> Warden configuration + # If you want to use other strategies, that are not supported by Devise, or + # change the failure app, you can configure them inside the config.warden block. + # + # config.warden do |manager| + # manager.intercept_401 = false + # manager.default_strategies(:scope => :user).unshift :some_external_strategy + # end + + # ==> Mountable engine configurations + # When using Devise inside an engine, let's call it `MyEngine`, and this engine + # is mountable, there are some extra configurations to be taken into account. + # The following options are available, assuming the engine is mounted as: + # + # mount MyEngine, at: "/my_engine" + # + # The router that invoked `devise_for`, in the example above, would be: + # config.router_name = :my_engine + # + # When using omniauth, Devise cannot automatically set Omniauth path, + # so you need to do it manually. For the users scope, it would be: + # config.omniauth_path_prefix = "/my_engine/users/auth" +end \ No newline at end of file diff --git a/config/initializers/formtastic.rb b/config/initializers/formtastic.rb new file mode 100644 index 00000000..69eaae95 --- /dev/null +++ b/config/initializers/formtastic.rb @@ -0,0 +1,79 @@ +# encoding: utf-8 + +# Set the default text field size when input is a string. Default is nil. +# Formtastic::FormBuilder.default_text_field_size = 50 + +# Set the default text area height when input is a text. Default is 20. +# Formtastic::FormBuilder.default_text_area_height = 5 + +# Set the default text area width when input is a text. Default is nil. +# Formtastic::FormBuilder.default_text_area_width = 50 + +# Should all fields be considered "required" by default? +# Defaults to true. +# Formtastic::FormBuilder.all_fields_required_by_default = true + +# Should select fields have a blank option/prompt by default? +# Defaults to true. +Formtastic::FormBuilder.include_blank_for_select_by_default = false + +# Set the string that will be appended to the labels/fieldsets which are required +# It accepts string or procs and the default is a localized version of +# '*'. In other words, if you configure formtastic.required +# in your locale, it will replace the abbr title properly. But if you don't want to use +# abbr tag, you can simply give a string as below +Formtastic::FormBuilder.required_string = "(required)" + +# Set the string that will be appended to the labels/fieldsets which are optional +# Defaults to an empty string ("") and also accepts procs (see required_string above) +# Formtastic::FormBuilder.optional_string = "(optional)" + +# Set the way inline errors will be displayed. +# Defaults to :sentence, valid options are :sentence, :list, :first and :none +# Formtastic::FormBuilder.inline_errors = :sentence +# Formtastic uses the following classes as default for hints, inline_errors and error list + +# If you override the class here, please ensure to override it in your stylesheets as well +# Formtastic::FormBuilder.default_hint_class = "inline-hints" +# Formtastic::FormBuilder.default_inline_error_class = "inline-errors" +# Formtastic::FormBuilder.default_error_list_class = "errors" + +# Set the method to call on label text to transform or format it for human-friendly +# reading when formtastic is used without object. Defaults to :humanize. +# Formtastic::FormBuilder.label_str_method = :humanize + +# Set the array of methods to try calling on parent objects in :select and :radio inputs +# for the text inside each @