Skip to content
Browse files

adding rails app

  • Loading branch information...
1 parent a92af7b commit decf1525b4d2bb11771f952f2bee6d3161530e38 @cameronyule cameronyule committed
Showing with 5,236 additions and 245 deletions.
  1. +19 −245 README
  2. +10 −0 Rakefile
  3. +19 −0 app/controllers/application.rb
  4. +102 −0 app/controllers/assets_controller.rb
  5. +43 −0 app/controllers/sessions_controller.rb
  6. +3 −0 app/helpers/application_helper.rb
  7. +2 −0 app/helpers/assets_helper.rb
  8. +2 −0 app/helpers/sessions_helper.rb
  9. +93 −0 app/helpers/users_helper.rb
  10. +29 −0 app/models/asset.rb
  11. +45 −0 app/models/user.rb
  12. BIN app/views/.DS_Store
  13. +1 −0 app/views/assets/edit.html.erb
  14. +30 −0 app/views/assets/index.html.erb
  15. +53 −0 app/views/assets/new.html.erb
  16. +5 −0 app/views/assets/show.html.erb
  17. +20 −0 app/views/layouts/layout.html.erb
  18. +16 −0 app/views/sessions/new.html.erb
  19. +109 −0 config/boot.rb
  20. +19 −0 config/database.yml
  21. +70 −0 config/environment.rb
  22. +17 −0 config/environments/development.rb
  23. +22 −0 config/environments/production.rb
  24. +22 −0 config/environments/test.rb
  25. +10 −0 config/initializers/inflections.rb
  26. +5 −0 config/initializers/mime_types.rb
  27. +15 −0 config/initializers/new_rails_defaults.rb
  28. +38 −0 config/initializers/site_keys.rb
  29. +30 −0 config/initializers/swfupload_session_hack.rb
  30. +48 −0 config/routes.rb
  31. +20 −0 db/migrate/20080731103639_create_assets.rb
  32. +22 −0 db/migrate/20080731103753_create_users.rb
  33. +42 −0 db/schema.rb
  34. +2 −0 doc/README_FOR_APP
  35. +187 −0 lib/authenticated_system.rb
  36. +11 −0 lib/authenticated_test_helper.rb
  37. +2,299 −0 log/development.log
  38. 0 log/production.log
  39. 0 log/server.log
  40. 0 log/test.log
  41. BIN public/.DS_Store
  42. +30 −0 public/404.html
  43. +30 −0 public/422.html
  44. +30 −0 public/500.html
  45. BIN public/assets/.DS_Store
  46. +10 −0 public/dispatch.cgi
  47. +24 −0 public/dispatch.fcgi
  48. +10 −0 public/dispatch.rb
  49. 0 public/favicon.ico
  50. BIN public/flash/swfupload_f9.swf
  51. BIN public/images/.DS_Store
  52. BIN public/javascripts/.DS_Store
  53. +755 −0 public/javascripts/swfupload.js
  54. +262 −0 public/javascripts/swfupload_handlers.js
  55. +5 −0 public/robots.txt
  56. BIN public/stylesheets/.DS_Store
  57. +226 −0 public/stylesheets/screen.css
  58. +3 −0 script/about
  59. +3 −0 script/console
  60. +3 −0 script/dbconsole
  61. +3 −0 script/destroy
  62. +3 −0 script/generate
  63. +3 −0 script/performance/benchmarker
  64. +3 −0 script/performance/profiler
  65. +3 −0 script/performance/request
  66. +3 −0 script/plugin
  67. +3 −0 script/process/inspector
  68. +3 −0 script/process/reaper
  69. +3 −0 script/process/spawner
  70. +3 −0 script/runner
  71. +3 −0 script/server
  72. +7 −0 test/fixtures/assets.yml
  73. +11 −0 test/fixtures/users.yml
  74. +8 −0 test/functional/assets_controller_test.rb
  75. +88 −0 test/functional/sessions_controller_test.rb
  76. +67 −0 test/functional/users_controller_test.rb
  77. +38 −0 test/test_helper.rb
  78. +8 −0 test/unit/asset_test.rb
  79. +103 −0 test/unit/user_test.rb
  80. BIN tmp/.DS_Store
  81. +1 −0 vendor/plugins/attachment_fu
  82. +1 −0 vendor/plugins/restful-authentication
View
264 README
@@ -1,256 +1,30 @@
-== Welcome to Rails
+swfupload-rails-authentication
+==============================
-Rails is a web-application framework that includes everything needed to create
-database-backed web applications according to the Model-View-Control pattern.
+Demo Rails 2.1 app showing SWFUpload working in tandem with restful-authentication, CSRF protection and attachment_fu.
-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.
+Requirements
+============
-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.
+Rails 2.1
+ImageMagick
+mini_magick gem
+mime-types gem
-== Getting Started
+Usage
+=====
-1. At the command prompt, start a new Rails application using the <tt>rails</tt> command
- and your application name. Ex: rails myapp
-2. Change directory into myapp and start the web server: <tt>script/server</tt> (run with --help for options)
-3. Go to http://localhost:3000/ and get "Welcome aboard: You're riding the Rails!"
-4. Follow the guidelines to start developing your application
+rake db:schema:load
+rake db:fixtures:load
+script/server
-== Web Servers
+Login
+=====
-By default, Rails will try to use Mongrel and lighttpd if they are installed, otherwise
-Rails will use WEBrick, the webserver that ships with Ruby. When you run script/server,
-Rails will check if Mongrel exists, then lighttpd and finally fall back to WEBrick. This ensures
-that you can always get up and running quickly.
+The restful authentication test user;
-Mongrel is a Ruby-based webserver with a C component (which requires compilation) that is
-suitable for development and deployment of Rails applications. If you have Ruby Gems installed,
-getting up and running with mongrel is as easy as: <tt>gem install mongrel</tt>.
-More info at: http://mongrel.rubyforge.org
-
-If Mongrel is not installed, Rails will look for lighttpd. It's considerably faster than
-Mongrel and WEBrick and also suited for production use, but requires additional
-installation and currently only works well on OS X/Unix (Windows users are encouraged
-to start with Mongrel). We recommend version 1.4.11 and higher. You can download it from
-http://www.lighttpd.net.
-
-And finally, if neither Mongrel or lighttpd are installed, Rails will use the built-in Ruby
-web server, WEBrick. WEBrick is a small Ruby web server suitable for development, but not
-for production.
-
-But of course its also possible to run Rails on any platform that supports FCGI.
-Apache, LiteSpeed, IIS are just a few. For more information on FCGI,
-please visit: http://wiki.rubyonrails.com/rails/pages/FastCGI
-
-
-== Apache .htaccess example
-
-# General Apache options
-AddHandler fastcgi-script .fcgi
-AddHandler cgi-script .cgi
-Options +FollowSymLinks +ExecCGI
-
-# If you don't want Rails to look in certain directories,
-# use the following rewrite rules so that Apache won't rewrite certain requests
-#
-# Example:
-# RewriteCond %{REQUEST_URI} ^/notrails.*
-# RewriteRule .* - [L]
-
-# Redirect all requests not available on the filesystem to Rails
-# By default the cgi dispatcher is used which is very slow
-#
-# For better performance replace the dispatcher with the fastcgi one
-#
-# Example:
-# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
-RewriteEngine On
-
-# If your Rails application is accessed via an Alias directive,
-# then you MUST also set the RewriteBase in this htaccess file.
-#
-# Example:
-# Alias /myrailsapp /path/to/myrailsapp/public
-# RewriteBase /myrailsapp
-
-RewriteRule ^$ index.html [QSA]
-RewriteRule ^([^.]+)$ $1.html [QSA]
-RewriteCond %{REQUEST_FILENAME} !-f
-RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
-
-# In case Rails experiences terminal errors
-# Instead of displaying this message you can supply a file here which will be rendered instead
-#
-# Example:
-# ErrorDocument 500 /500.html
-
-ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
-
-
-== 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/ including:
-
-* The Learning Ruby (Pickaxe) Book: http://www.ruby-doc.org/docs/ProgrammingRuby/
-* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
-
-These two online (and free) 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 'gem install ruby-debug'
-Example:
-
- class WeblogController < ActionController::Base
- def index
- @posts = Post.find(: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
- => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
- #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
- >> @posts.first.title = "hello from a debugger"
- => "hello from a debugger"
-
-...and even better is that you can examine how your runtime objects actually work:
-
- >> f = @posts.first
- => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
- >> f.
- Display all 152 possibilities? (y or n)
-
-Finally, when you're ready to resume execution, you enter "cont"
-
-
-== Console
-
-You can interact with the domain model by starting the console through <tt>script/console</tt>.
-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.
-Passing an argument will specify a different environment, like <tt>script/console production</tt>.
-
-To reload your controllers and models after launching the console run <tt>reload!</tt>
-
-== dbconsole
-
-You can go to the command line of your database directly through <tt>script/dbconsole</tt>.
-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 <tt>script/dbconsole production</tt>.
-Currently works for mysql, postgresql and sqlite.
-
-== Description of Contents
-
-app
- Holds all the code that's specific to this particular application.
-
-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.
- Most models will descend from ActiveRecord::Base.
-
-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.
-
-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
- <tt>layout :default</tt> 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 script/generate 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 <tt>rake doc:app</tt>
-
-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. Contains subdirectories for images, stylesheets,
- and javascripts. 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 script/generate scripts, 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.
+username: quentin
+password: monkey
View
10 Rakefile
@@ -0,0 +1,10 @@
+# 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.join(File.dirname(__FILE__), 'config', 'boot'))
+
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+require 'tasks/rails'
View
19 app/controllers/application.rb
@@ -0,0 +1,19 @@
+# Filters added to this controller apply to all controllers in the application.
+# Likewise, all the methods added will be available for all controllers.
+
+class ApplicationController < ActionController::Base
+
+ include AuthenticatedSystem
+
+ helper :all # include all helpers, all the time
+
+ # See ActionController::RequestForgeryProtection for details
+ # Uncomment the :secret if you're not using the cookie session store
+ protect_from_forgery #:secret => 'd307747927b72d71553b39b15089e7da'
+
+ # See ActionController::Base for details
+ # Uncomment this to filter the contents of submitted sensitive data parameters
+ # from your application log (in this case, all fields with names like "password").
+ # filter_parameter_logging :password
+
+end
View
102 app/controllers/assets_controller.rb
@@ -0,0 +1,102 @@
+class AssetsController < ApplicationController
+
+ layout 'layout'
+
+ session :cookie_only => false, :only => :create
+
+ before_filter :login_required
+
+ # GET /assets
+ # GET /assets.xml
+ def index
+ @assets = Asset.masters
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.xml { render :xml => @assets }
+ end
+ end
+
+ # GET /assets/1
+ # GET /assets/1.xml
+ def show
+ @asset = Asset.find(params[:id])
+
+ respond_to do |format|
+ format.html # show.html.erb
+ format.xml { render :xml => @asset }
+ end
+ end
+
+ # GET /assets/new
+ # GET /assets/new.xml
+ def new
+ @asset = Asset.new
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.xml { render :xml => @asset }
+ end
+ end
+
+ # GET /assets/1/edit
+ def edit
+ @asset = Asset.find(params[:id])
+ end
+
+ # POST /assets
+ # POST /assets.xml
+ def create
+ @asset = Asset.new(params[:asset])
+
+ respond_to do |format|
+ if params[:Filedata]
+ @asset = Asset.new :swf_uploaded_data => params[:Filedata]
+ @asset.user = current_user
+ @asset.save!
+
+ format.html { render :text => @asset.public_filename(:thumb) }
+ format.xml { render :nothing => true }
+ else
+ if @asset.save
+ flash[:notice] = 'Created'
+ format.html { redirect_to(@asset) }
+ format.xml { render :xml => @asset, :status => :created, :location => @asset }
+ else
+ format.html { render :action => "new" }
+ format.xml { render :xml => @asset.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+ end
+
+ # PUT /assets/1
+ # PUT /assets/1.xml
+ def update
+ @asset = Asset.find(params[:id])
+
+ respond_to do |format|
+ if @asset.update_attributes(params[:asset])
+ flash[:notice] = 'Updated'
+ format.html { redirect_to(@asset) }
+ format.xml { head :ok }
+ else
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @asset.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /assets/1
+ # DELETE /assets/1.xml
+ def destroy
+ @asset = Asset.find(params[:id])
+ @asset.destroy
+
+ respond_to do |format|
+ format.html { redirect_to(assets_url) }
+ format.xml { head :ok }
+ end
+ end
+
+end
View
43 app/controllers/sessions_controller.rb
@@ -0,0 +1,43 @@
+# This controller handles the login/logout function of the site.
+class SessionsController < ApplicationController
+ # Be sure to include AuthenticationSystem in Application Controller instead
+ include AuthenticatedSystem
+
+ # render new.rhtml
+ def new
+ end
+
+ def create
+ logout_keeping_session!
+ user = User.authenticate(params[:login], params[:password])
+ if user
+ # Protects against session fixation attacks, causes request forgery
+ # protection if user resubmits an earlier form using back
+ # button. Uncomment if you understand the tradeoffs.
+ # reset_session
+ self.current_user = user
+ new_cookie_flag = (params[:remember_me] == "1")
+ handle_remember_cookie! new_cookie_flag
+ redirect_back_or_default('/')
+ flash[:notice] = "Logged in successfully"
+ else
+ note_failed_signin
+ @login = params[:login]
+ @remember_me = params[:remember_me]
+ render :action => 'new'
+ end
+ end
+
+ def destroy
+ logout_killing_session!
+ flash[:notice] = "You have been logged out."
+ redirect_back_or_default('/')
+ end
+
+protected
+ # Track failed login attempts
+ def note_failed_signin
+ flash[:error] = "Couldn't log you in as '#{params[:login]}'"
+ logger.warn "Failed login for '#{params[:login]}' from #{request.remote_ip} at #{Time.now.utc}"
+ end
+end
View
3 app/helpers/application_helper.rb
@@ -0,0 +1,3 @@
+# Methods added to this helper will be available to all templates in the application.
+module ApplicationHelper
+end
View
2 app/helpers/assets_helper.rb
@@ -0,0 +1,2 @@
+module AssetsHelper
+end
View
2 app/helpers/sessions_helper.rb
@@ -0,0 +1,2 @@
+module SessionsHelper
+end
View
93 app/helpers/users_helper.rb
@@ -0,0 +1,93 @@
+module UsersHelper
+
+ #
+ # Use this to wrap view elements that the user can't access.
+ # !! Note: this is an *interface*, not *security* feature !!
+ # You need to do all access control at the controller level.
+ #
+ # Example:
+ # <%= if_authorized?(:index, User) do link_to('List all users', users_path) end %> |
+ # <%= if_authorized?(:edit, @user) do link_to('Edit this user', edit_user_path) end %> |
+ # <%= if_authorized?(:destroy, @user) do link_to 'Destroy', @user, :confirm => 'Are you sure?', :method => :delete end %>
+ #
+ #
+ def if_authorized?(action, resource, &block)
+ if authorized?(action, resource)
+ yield action, resource
+ end
+ end
+
+ #
+ # Link to user's page ('users/1')
+ #
+ # By default, their login is used as link text and link title (tooltip)
+ #
+ # Takes options
+ # * :content_text => 'Content text in place of user.login', escaped with
+ # the standard h() function.
+ # * :content_method => :user_instance_method_to_call_for_content_text
+ # * :title_method => :user_instance_method_to_call_for_title_attribute
+ # * as well as link_to()'s standard options
+ #
+ # Examples:
+ # link_to_user @user
+ # # => <a href="/users/3" title="barmy">barmy</a>
+ #
+ # # if you've added a .name attribute:
+ # content_tag :span, :class => :vcard do
+ # (link_to_user user, :class => 'fn n', :title_method => :login, :content_method => :name) +
+ # ': ' + (content_tag :span, user.email, :class => 'email')
+ # end
+ # # => <span class="vcard"><a href="/users/3" title="barmy" class="fn n">Cyril Fotheringay-Phipps</a>: <span class="email">barmy@blandings.com</span></span>
+ #
+ # link_to_user @user, :content_text => 'Your user page'
+ # # => <a href="/users/3" title="barmy" class="nickname">Your user page</a>
+ #
+ def link_to_user(user, options={})
+ raise "Invalid user" unless user
+ options.reverse_merge! :content_method => :login, :title_method => :login, :class => :nickname
+ content_text = options.delete(:content_text)
+ content_text ||= user.send(options.delete(:content_method))
+ options[:title] ||= user.send(options.delete(:title_method))
+ link_to h(content_text), user_path(user), options
+ end
+
+ #
+ # Link to login page using remote ip address as link content
+ #
+ # The :title (and thus, tooltip) is set to the IP address
+ #
+ # Examples:
+ # link_to_login_with_IP
+ # # => <a href="/login" title="169.69.69.69">169.69.69.69</a>
+ #
+ # link_to_login_with_IP :content_text => 'not signed in'
+ # # => <a href="/login" title="169.69.69.69">not signed in</a>
+ #
+ def link_to_login_with_IP content_text=nil, options={}
+ ip_addr = request.remote_ip
+ content_text ||= ip_addr
+ options.reverse_merge! :title => ip_addr
+ if tag = options.delete(:tag)
+ content_tag tag, h(content_text), options
+ else
+ link_to h(content_text), login_path, options
+ end
+ end
+
+ #
+ # Link to the current user's page (using link_to_user) or to the login page
+ # (using link_to_login_with_IP).
+ #
+ def link_to_current_user(options={})
+ if current_user
+ link_to_user current_user, options
+ else
+ content_text = options.delete(:content_text) || 'not signed in'
+ # kill ignored options from link_to_user
+ [:content_method, :title_method].each{|opt| options.delete(opt)}
+ link_to_login_with_IP content_text, options
+ end
+ end
+
+end
View
29 app/models/asset.rb
@@ -0,0 +1,29 @@
+require 'mime/types'
+
+class Asset < ActiveRecord::Base
+
+ # Relationships
+ belongs_to :user
+
+ has_attachment :storage => :file_system,
+ :max_size => 5.megabytes,
+ :resize_to => '800x600>',
+ :thumbnails => { :thumb => '150x150>' },
+ :processor => :MiniMagick
+
+
+ # Validations
+ validates_as_attachment
+
+ #
+ named_scope :masters, :conditions => {:parent_id => nil}
+
+ # Map file extensions to mime types.
+ # Thanks to bug in Flash 8 the content type is always set to application/octet-stream.
+ # From: http://blog.airbladesoftware.com/2007/8/8/uploading-files-with-swfupload
+ def swf_uploaded_data=(data)
+ data.content_type = MIME::Types.type_for(data.original_filename)
+ self.uploaded_data = data
+ end
+
+end
View
45 app/models/user.rb
@@ -0,0 +1,45 @@
+require 'digest/sha1'
+
+class User < ActiveRecord::Base
+ include Authentication
+ include Authentication::ByPassword
+ include Authentication::ByCookieToken
+
+ validates_presence_of :login
+ validates_length_of :login, :within => 3..40
+ validates_uniqueness_of :login, :case_sensitive => false
+ validates_format_of :login, :with => RE_LOGIN_OK, :message => MSG_LOGIN_BAD
+
+ validates_format_of :name, :with => RE_NAME_OK, :message => MSG_NAME_BAD, :allow_nil => true
+ validates_length_of :name, :maximum => 100
+
+ validates_presence_of :email
+ validates_length_of :email, :within => 6..100 #r@a.wk
+ validates_uniqueness_of :email, :case_sensitive => false
+ validates_format_of :email, :with => RE_EMAIL_OK, :message => MSG_EMAIL_BAD
+
+
+
+ # HACK HACK HACK -- how to do attr_accessible from here?
+ # prevents a user from submitting a crafted form that bypasses activation
+ # anything else you want your user to change should be added here.
+ attr_accessible :login, :email, :name, :password, :password_confirmation
+
+
+
+ # Authenticates a user by their login name and unencrypted password. Returns the user or nil.
+ #
+ # uff. this is really an authorization, not authentication routine.
+ # We really need a Dispatch Chain here or something.
+ # This will also let us return a human error message.
+ #
+ def self.authenticate(login, password)
+ u = find_by_login(login) # need to get the salt
+ u && u.authenticated?(password) ? u : nil
+ end
+
+ protected
+
+
+
+end
View
BIN app/views/.DS_Store
Binary file not shown.
View
1 app/views/assets/edit.html.erb
@@ -0,0 +1 @@
+<h1>Edit</h1>
View
30 app/views/assets/index.html.erb
@@ -0,0 +1,30 @@
+<table>
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>File size</th>
+ <th>File Type</th>
+ <th>Author</th>
+ <th>Updated</th>
+ </tr>
+ </thead>
+ <tbody>
+ <% unless @assets.blank? %>
+ <% @assets.each do |asset| -%>
+ <tr>
+ <td><%= link_to image_tag(asset.public_filename(:thumb)), asset %></td>
+ <td><%= number_to_human_size(asset.size) %></td>
+ <td><%= h asset.content_type %></td>
+ <td><%= h asset.user.login %></td>
+ <td><%= asset.updated_at.to_s(:full) %></td>
+ </tr>
+ <% end -%>
+ <% else -%>
+ <tr>
+ <td colspan="5">No assets found.</td>
+ </tr>
+ <% end -%>
+ </tbody>
+</table>
+
+<p><%= link_to "new asset", new_asset_path %></p>
View
53 app/views/assets/new.html.erb
@@ -0,0 +1,53 @@
+<h1>New</h1>
+
+<script type='text/javascript'>
+ var swfu;
+
+ window.onload = function () {
+ swfu = new SWFUpload({
+ upload_url : '<%= assets_path -%>?_swfupload_demo_session=<%= u session.session_id %>',
+ flash_url : '/flash/swfupload_f9.swf',
+
+ file_size_limit : '10000',
+ file_types : '*.jpg',
+ file_types_description : 'JPG Images',
+ file_upload_limit : '0',
+
+ file_queue_error_handler : fileQueueError,
+ file_dialog_complete_handler : fileDialogComplete,
+ upload_progress_handler : uploadProgress,
+ upload_error_handler : uploadError,
+ upload_success_handler : uploadSuccess,
+ upload_complete_handler : uploadComplete,
+
+ post_params : {
+ authenticity_token : '<%= u form_authenticity_token -%>',
+ },
+
+ custom_settings : {
+ upload_target : 'divFileProgressContainer',
+ },
+
+ debug: false
+
+ });
+ };
+</script>
+
+<div style="margin: 0px 10px;">
+ <div>
+
+ <% form_for(@asset) do |f| %>
+ <fieldset>
+ <button id="btnBrowse" type="button" style="padding: 5px;" onclick="swfu.selectFiles(); this.blur();">
+ Select Files <span style="font-size: 7pt;">(5 MB Max)</span>
+ </button>
+ </fieldset>
+ <% end %>
+
+ </div>
+ <div id="divFileProgressContainer" style="height: 75px;"></div>
+ <div id="thumbnails"></div>
+
+ <p><%= link_to 'back', assets_path %></p>
+</div>
View
5 app/views/assets/show.html.erb
@@ -0,0 +1,5 @@
+<%= image_tag(@asset.public_filename) %>
+
+<%= debug @asset %>
+
+<%= link_to 'back', assets_path %>
View
20 app/views/layouts/layout.html.erb
@@ -0,0 +1,20 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-GB">
+
+<head>
+
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+ <title>SWFUpload Test</title>
+
+ <%= stylesheet_link_tag 'screen', :media => 'screen' %>
+ <%= javascript_include_tag 'swfupload', 'swfupload_handlers' %>
+
+</head>
+
+<body>
+ <div class="container">
+ <%= yield %>
+ </div>
+</body>
+</html>
View
16 app/views/sessions/new.html.erb
@@ -0,0 +1,16 @@
+<h1>Log In</h1>
+
+<% form_tag session_path do -%>
+<p><label for="login">Login</label><br/>
+<%= text_field_tag 'login', @login %></p>
+
+<p><label for="password">Password</label><br/>
+<%= password_field_tag 'password', nil %></p>
+
+<!-- Uncomment this if you want this functionality
+<p><label for="remember_me">Remember me:</label>
+<%= check_box_tag 'remember_me', '1', @remember_me %></p>
+-->
+
+<p><%= submit_tag 'Log in' %></p>
+<% end -%>
View
109 config/boot.rb
@@ -0,0 +1,109 @@
+# Don't change this file!
+# Configure your app in config/environment.rb and config/environments/*.rb
+
+RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
+
+module Rails
+ class << self
+ def boot!
+ unless booted?
+ preinitialize
+ pick_boot.run
+ end
+ end
+
+ def booted?
+ defined? Rails::Initializer
+ end
+
+ def pick_boot
+ (vendor_rails? ? VendorBoot : GemBoot).new
+ end
+
+ def vendor_rails?
+ File.exist?("#{RAILS_ROOT}/vendor/rails")
+ end
+
+ def preinitialize
+ load(preinitializer_path) if File.exist?(preinitializer_path)
+ end
+
+ def preinitializer_path
+ "#{RAILS_ROOT}/config/preinitializer.rb"
+ end
+ end
+
+ class Boot
+ def run
+ load_initializer
+ Rails::Initializer.run(:set_load_path)
+ end
+ end
+
+ class VendorBoot < Boot
+ def load_initializer
+ require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
+ Rails::Initializer.run(:install_gem_spec_stubs)
+ end
+ end
+
+ class GemBoot < Boot
+ def load_initializer
+ self.class.load_rubygems
+ load_rails_gem
+ require 'initializer'
+ end
+
+ def load_rails_gem
+ if version = self.class.gem_version
+ gem 'rails', version
+ else
+ gem 'rails'
+ end
+ rescue Gem::LoadError => load_error
+ $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
+ exit 1
+ end
+
+ class << self
+ def rubygems_version
+ Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion
+ end
+
+ def gem_version
+ if defined? RAILS_GEM_VERSION
+ RAILS_GEM_VERSION
+ elsif ENV.include?('RAILS_GEM_VERSION')
+ ENV['RAILS_GEM_VERSION']
+ else
+ parse_gem_version(read_environment_rb)
+ end
+ end
+
+ def load_rubygems
+ require 'rubygems'
+
+ unless rubygems_version >= '0.9.4'
+ $stderr.puts %(Rails requires RubyGems >= 0.9.4 (you have #{rubygems_version}). Please `gem update --system` and try again.)
+ exit 1
+ end
+
+ rescue LoadError
+ $stderr.puts %(Rails requires RubyGems >= 0.9.4. Please install RubyGems and try again: http://rubygems.rubyforge.org)
+ exit 1
+ end
+
+ def parse_gem_version(text)
+ $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
+ end
+
+ private
+ def read_environment_rb
+ File.read("#{RAILS_ROOT}/config/environment.rb")
+ end
+ end
+ end
+end
+
+# All that for this:
+Rails.boot!
View
19 config/database.yml
@@ -0,0 +1,19 @@
+# SQLite version 3.x
+# gem install sqlite3-ruby (not necessary on OS X Leopard)
+development:
+ adapter: sqlite3
+ database: db/development.sqlite3
+ 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
+ timeout: 5000
+
+production:
+ adapter: sqlite3
+ database: db/production.sqlite3
+ timeout: 5000
View
70 config/environment.rb
@@ -0,0 +1,70 @@
+# Be sure to restart your server when you modify this file
+
+# Uncomment below to force Rails into production mode when
+# you don't control web/app server and can't set it the proper way
+# ENV['RAILS_ENV'] ||= 'production'
+
+# Specifies gem version of Rails to use when vendor/rails is not present
+RAILS_GEM_VERSION = '2.1.0' unless defined? RAILS_GEM_VERSION
+
+# Bootstrap the Rails environment, frameworks, and default configuration
+require File.join(File.dirname(__FILE__), 'boot')
+
+Rails::Initializer.run do |config|
+ # 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.
+ # See Rails::Configuration for more options.
+
+ # Skip frameworks you're not going to use. To use Rails without a database
+ # you must remove the Active Record framework.
+ # config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
+
+ # Specify gems that this application depends on.
+ # They can then be installed with "rake gems:install" on new installations.
+ # config.gem "bj"
+ # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
+ # config.gem "aws-s3", :lib => "aws/s3"
+
+ config.gem 'mini_magick'
+ config.gem 'mime-types', :lib => 'mime/types'
+
+ # Only load the plugins named here, in the order given. By default, all plugins
+ # in vendor/plugins are loaded in alphabetical order.
+ # :all can be used as a placeholder for all plugins not explicitly named
+ # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
+
+ # Add additional load paths for your own custom dirs
+ # config.load_paths += %W( #{RAILS_ROOT}/extras )
+
+ # Force all environments to use the same logger level
+ # (by default production uses :info, the others :debug)
+ # config.log_level = :debug
+
+ # Make Time.zone default to the specified zone, and make Active Record store time values
+ # in the database in UTC, and return them converted to the specified local zone.
+ # Run "rake -D time" for a list of tasks for finding time zone names. Uncomment to use default local time.
+ config.time_zone = 'UTC'
+
+ # Your secret key for verifying cookie session data integrity.
+ # If you change this key, all old sessions will become invalid!
+ # Make sure the secret is at least 30 characters and all random,
+ # no regular words or you'll be exposed to dictionary attacks.
+ config.action_controller.session = {
+ :session_key => '_swfupload_demo_session',
+ :secret => '1a72951ead92ea6e739efa07a4fcb2ca5a752f2e1143609d11a2d217eaa8cfa827d5f1c97af1470797db9fb417d0c6af0fe2b486f5c2760a5e258a8793c89294'
+ }
+
+ # Use the database for sessions instead of the cookie-based default,
+ # which shouldn't be used to store highly confidential information
+ # (create the session table with "rake db:sessions:create")
+ # config.action_controller.session_store = :active_record_store
+
+ # Use SQL instead of Active Record's schema dumper when creating the test 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
+
+ # Activate observers that should always be running
+ # config.active_record.observers = :cacher, :garbage_collector
+end
View
17 config/environments/development.rb
@@ -0,0 +1,17 @@
+# Settings specified here will take precedence over those in config/environment.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 webserver 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.action_controller.consider_all_requests_local = true
+config.action_view.debug_rjs = true
+config.action_controller.perform_caching = false
+
+# Don't care if the mailer can't send
+config.action_mailer.raise_delivery_errors = false
View
22 config/environments/production.rb
@@ -0,0 +1,22 @@
+# Settings specified here will take precedence over those in config/environment.rb
+
+# The production environment is meant for finished, "live" apps.
+# Code is not reloaded between requests
+config.cache_classes = true
+
+# Use a different logger for distributed setups
+# config.logger = SyslogLogger.new
+
+# Full error reports are disabled and caching is turned on
+config.action_controller.consider_all_requests_local = false
+config.action_controller.perform_caching = true
+config.action_view.cache_template_loading = true
+
+# 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"
+
+# Disable delivery errors, bad email addresses will be ignored
+# config.action_mailer.raise_delivery_errors = false
View
22 config/environments/test.rb
@@ -0,0 +1,22 @@
+# Settings specified here will take precedence over those in config/environment.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
+
+# Log error messages when you accidentally call methods on nil.
+config.whiny_nils = true
+
+# Show full error reports and disable caching
+config.action_controller.consider_all_requests_local = true
+config.action_controller.perform_caching = 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
View
10 config/initializers/inflections.rb
@@ -0,0 +1,10 @@
+# Be sure to restart your server when you modify this file.
+
+# Add new inflection rules using the following format
+# (all these examples are active by default):
+# Inflector.inflections do |inflect|
+# inflect.plural /^(ox)$/i, '\1en'
+# inflect.singular /^(ox)en/i, '\1'
+# inflect.irregular 'person', 'people'
+# inflect.uncountable %w( fish sheep )
+# end
View
5 config/initializers/mime_types.rb
@@ -0,0 +1,5 @@
+# Be sure to restart your server when you modify this file.
+
+# Add new mime types for use in respond_to blocks:
+# Mime::Type.register "text/richtext", :rtf
+# Mime::Type.register_alias "text/html", :iphone
View
15 config/initializers/new_rails_defaults.rb
@@ -0,0 +1,15 @@
+# These settings change the behavior of Rails 2 apps and will be defaults
+# for Rails 3. You can remove this initializer when Rails 3 is released.
+
+# Include Active Record class name as root for JSON serialized output.
+ActiveRecord::Base.include_root_in_json = true
+
+# Store the full class name (including module namespace) in STI type column.
+ActiveRecord::Base.store_full_sti_class = true
+
+# Use ISO 8601 format for JSON serialized times and dates.
+ActiveSupport.use_standard_json_time_format = true
+
+# Don't escape HTML entities in JSON, leave that for the #json_escape helper.
+# if you're including raw json in an HTML page.
+ActiveSupport.escape_html_entities_in_json = false
View
38 config/initializers/site_keys.rb
@@ -0,0 +1,38 @@
+
+# A Site key gives additional protection against a dictionary attack if your
+# DB is ever compromised. With no site key, we store
+# DB_password = hash(user_password, DB_user_salt)
+# If your database were to be compromised you'd be vulnerable to a dictionary
+# attack on all your stupid users' passwords. With a site key, we store
+# DB_password = hash(user_password, DB_user_salt, Code_site_key)
+# That means an attacker needs access to both your site's code *and* its
+# database to mount an "offline dictionary attack.":http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/web-authentication.html
+#
+# It's probably of minor importance, but recommended by best practices: 'defense
+# in depth'. Needless to say, if you upload this to github or the youtubes or
+# otherwise place it in public view you'll kinda defeat the point. Your users'
+# passwords are still secure, and the world won't end, but defense_in_depth -= 1.
+#
+# Please note: if you change this, all the passwords will be invalidated, so DO
+# keep it someplace secure. Use the random value given or type in the lyrics to
+# your favorite Jay-Z song or something; any moderately long, unpredictable text.
+REST_AUTH_SITE_KEY = '166db9b006217ca25828be5ca0f664b19fe332cd'
+
+# Repeated applications of the hash make brute force (even with a compromised
+# database and site key) harder, and scale with Moore's law.
+#
+# bq. "To squeeze the most security out of a limited-entropy password or
+# passphrase, we can use two techniques [salting and stretching]... that are
+# so simple and obvious that they should be used in every password system.
+# There is really no excuse not to use them." http://tinyurl.com/37lb73
+# Practical Security (Ferguson & Scheier) p350
+#
+# A modest 10 foldings (the default here) adds 3ms. This makes brute forcing 10
+# times harder, while reducing an app that otherwise serves 100 reqs/s to 78 signin
+# reqs/s, an app that does 10reqs/s to 9.7 reqs/s
+#
+# More:
+# * http://www.owasp.org/index.php/Hashing_Java
+# * "An Illustrated Guide to Cryptographic Hashes":http://www.unixwiz.net/techtips/iguide-crypto-hashes.html
+
+REST_AUTH_DIGEST_STRETCHES = 10
View
30 config/initializers/swfupload_session_hack.rb
@@ -0,0 +1,30 @@
+# hacks for swfupload + cookie store to work
+# see http://blog.airbladesoftware.com/2007/8/8/uploading-files-with-swfupload
+
+class CGI::Session
+ alias original_initialize initialize
+ def initialize(request, option = {})
+ session_key = option['session_key'] || '_session_id'
+ query_string = if (qs = request.env_table["QUERY_STRING"]) and qs != ""
+ qs
+ elsif (ru = request.env_table["REQUEST_URI"][0..-1]).include?("?")
+ ru[(ru.index("?") + 1)..-1]
+ end
+ if query_string and query_string.include?(session_key)
+ option['session_data'] = CGI.unescape(query_string.scan(/#{session_key}=(.*?)(&.*?)*$/).flatten.first)
+ end
+ original_initialize(request, option)
+ end
+end
+
+class CGI::Session::CookieStore
+ alias original_initialize initialize
+ def initialize(session, options = {})
+ @session_data = options['session_data']
+ original_initialize(session, options)
+ end
+
+ def read_cookie
+ @session_data || @session.cgi.cookies[@cookie_options['name']].first
+ end
+end
View
48 config/routes.rb
@@ -0,0 +1,48 @@
+ActionController::Routing::Routes.draw do |map|
+ # The priority is based upon order of creation: first created -> highest priority.
+
+ # Sample of regular route:
+ # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
+ # Keep in mind you can assign values other than :controller and :action
+
+ # Sample of named route:
+ # map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'
+ # This route can be invoked with purchase_url(:id => product.id)
+
+ # Sample resource route (maps HTTP verbs to controller actions automatically):
+ # map.resources :products
+
+ # Sample resource route with options:
+ # map.resources :products, :member => { :short => :get, :toggle => :post }, :collection => { :sold => :get }
+
+ # Sample resource route with sub-resources:
+ # map.resources :products, :has_many => [ :comments, :sales ], :has_one => :seller
+
+ # Sample resource route with more complex sub-resources
+ # map.resources :products do |products|
+ # products.resources :comments
+ # products.resources :sales, :collection => { :recent => :get }
+ # end
+
+ # Sample resource route within a namespace:
+ # map.namespace :admin do |admin|
+ # # Directs /admin/products/* to Admin::ProductsController (app/controllers/admin/products_controller.rb)
+ # admin.resources :products
+ # end
+
+ # You can have the root of your site routed with map.root -- just remember to delete public/index.html.
+ map.root :controller => "assets"
+
+ map.logout '/logout', :controller => 'sessions', :action => 'destroy'
+ map.login '/login', :controller => 'sessions', :action => 'new'
+
+ map.resource :session
+
+ map.resources :assets
+
+ # See how all your routes lay out with "rake routes"
+
+ # Install the default routes as the lowest priority.
+ map.connect ':controller/:action/:id'
+ map.connect ':controller/:action/:id.:format'
+end
View
20 db/migrate/20080731103639_create_assets.rb
@@ -0,0 +1,20 @@
+class CreateAssets < ActiveRecord::Migration
+ def self.up
+ create_table :assets do |t|
+ t.string :name
+ t.string :filename
+ t.string :content_type
+ t.integer :size
+ t.integer :width
+ t.integer :height
+ t.string :thumbnail
+ t.integer :user_id
+ t.integer :parent_id
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :assets
+ end
+end
View
22 db/migrate/20080731103753_create_users.rb
@@ -0,0 +1,22 @@
+class CreateUsers < ActiveRecord::Migration
+ def self.up
+ create_table "users", :force => true do |t|
+ t.column :login, :string, :limit => 40
+ t.column :name, :string, :limit => 100, :default => '', :null => true
+ t.column :email, :string, :limit => 100
+ t.column :crypted_password, :string, :limit => 40
+ t.column :salt, :string, :limit => 40
+ t.column :created_at, :datetime
+ t.column :updated_at, :datetime
+ t.column :remember_token, :string, :limit => 40
+ t.column :remember_token_expires_at, :datetime
+
+
+ end
+ add_index :users, :login, :unique => true
+ end
+
+ def self.down
+ drop_table "users"
+ end
+end
View
42 db/schema.rb
@@ -0,0 +1,42 @@
+# This file is auto-generated from the current state of the database. Instead of editing this file,
+# please use the migrations feature of Active Record to incrementally modify your database, and
+# then regenerate this schema definition.
+#
+# Note that this schema.rb definition is the authoritative source for your database schema. If you need
+# to create the application database on another system, you should be using db:schema:load, not running
+# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
+# you'll amass, the slower it'll run and the greater likelihood for issues).
+#
+# It's strongly recommended to check this file into your version control system.
+
+ActiveRecord::Schema.define(:version => 20080731103753) do
+
+ create_table "assets", :force => true do |t|
+ t.string "name"
+ t.string "filename"
+ t.string "content_type"
+ t.integer "size"
+ t.integer "width"
+ t.integer "height"
+ t.string "thumbnail"
+ t.integer "user_id"
+ t.integer "parent_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ create_table "users", :force => true do |t|
+ t.string "login", :limit => 40
+ t.string "name", :limit => 100, :default => ""
+ t.string "email", :limit => 100
+ t.string "crypted_password", :limit => 40
+ t.string "salt", :limit => 40
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "remember_token", :limit => 40
+ t.datetime "remember_token_expires_at"
+ end
+
+ add_index "users", ["login"], :name => "index_users_on_login", :unique => true
+
+end
View
2 doc/README_FOR_APP
@@ -0,0 +1,2 @@
+Use this README file to introduce your application and point to useful places in the API for learning more.
+Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
View
187 lib/authenticated_system.rb
@@ -0,0 +1,187 @@
+module AuthenticatedSystem
+ protected
+ # Returns true or false if the user is logged in.
+ # Preloads @current_user with the user model if they're logged in.
+ def logged_in?
+ !!current_user
+ end
+
+ # Accesses the current user from the session.
+ # Future calls avoid the database because nil is not equal to false.
+ def current_user
+ @current_user ||= (login_from_session || login_from_basic_auth || login_from_cookie) unless @current_user == false
+ end
+
+ # Store the given user id in the session.
+ def current_user=(new_user)
+ session[:user_id] = new_user ? new_user.id : nil
+ @current_user = new_user || false
+ end
+
+ # Check if the user is authorized
+ #
+ # Override this method in your controllers if you want to restrict access
+ # to only a few actions or if you want to check if the user
+ # has the correct rights.
+ #
+ # Example:
+ #
+ # # only allow nonbobs
+ # def authorized?
+ # current_user.login != "bob"
+ # end
+ #
+ def authorized?(action=nil, resource=nil, *args)
+ logged_in?
+ end
+
+ # Filter method to enforce a login requirement.
+ #
+ # To require logins for all actions, use this in your controllers:
+ #
+ # before_filter :login_required
+ #
+ # To require logins for specific actions, use this in your controllers:
+ #
+ # before_filter :login_required, :only => [ :edit, :update ]
+ #
+ # To skip this in a subclassed controller:
+ #
+ # skip_before_filter :login_required
+ #
+ def login_required
+ authorized? || access_denied
+ end
+
+ # Redirect as appropriate when an access request fails.
+ #
+ # The default action is to redirect to the login screen.
+ #
+ # Override this method in your controllers if you want to have special
+ # behavior in case the user is not authorized
+ # to access the requested action. For example, a popup window might
+ # simply close itself.
+ def access_denied
+ respond_to do |format|
+ format.html do
+ store_location
+ redirect_to new_session_path
+ end
+ # format.any doesn't work in rails version < http://dev.rubyonrails.org/changeset/8987
+ # you may want to change format.any to e.g. format.any(:js, :xml)
+ format.any do
+ request_http_basic_authentication 'Web Password'
+ end
+ end
+ end
+
+ # Store the URI of the current request in the session.
+ #
+ # We can return to this location by calling #redirect_back_or_default.
+ def store_location
+ session[:return_to] = request.request_uri
+ end
+
+ # Redirect to the URI stored by the most recent store_location call or
+ # to the passed default. Set an appropriately modified
+ # after_filter :store_location, :only => [:index, :new, :show, :edit]
+ # for any controller you want to be bounce-backable.
+ def redirect_back_or_default(default)
+ redirect_to(session[:return_to] || default)
+ session[:return_to] = nil
+ end
+
+ # Inclusion hook to make #current_user and #logged_in?
+ # available as ActionView helper methods.
+ def self.included(base)
+ base.send :helper_method, :current_user, :logged_in?, :authorized? if base.respond_to? :helper_method
+ end
+
+ #
+ # Login
+ #
+
+ # Called from #current_user. First attempt to login by the user id stored in the session.
+ def login_from_session
+ self.current_user = User.find_by_id(session[:user_id]) if session[:user_id]
+ end
+
+ # Called from #current_user. Now, attempt to login by basic authentication information.
+ def login_from_basic_auth
+ authenticate_with_http_basic do |login, password|
+ self.current_user = User.authenticate(login, password)
+ end
+ end
+
+ #
+ # Logout
+ #
+
+ # Called from #current_user. Finaly, attempt to login by an expiring token in the cookie.
+ # for the paranoid: we _should_ be storing user_token = hash(cookie_token, request IP)
+ def login_from_cookie
+ user = cookies[:auth_token] && User.find_by_remember_token(cookies[:auth_token])
+ if user && user.remember_token?
+ self.current_user = user
+ handle_remember_cookie! false # freshen cookie token (keeping date)
+ self.current_user
+ end
+ end
+
+ # This is ususally what you want; resetting the session willy-nilly wreaks
+ # havoc with forgery protection, and is only strictly necessary on login.
+ # However, **all session state variables should be unset here**.
+ def logout_keeping_session!
+ # Kill server-side auth cookie
+ @current_user.forget_me if @current_user.is_a? User
+ @current_user = false # not logged in, and don't do it for me
+ kill_remember_cookie! # Kill client-side auth cookie
+ session[:user_id] = nil # keeps the session but kill our variable
+ # explicitly kill any other session variables you set
+ end
+
+ # The session should only be reset at the tail end of a form POST --
+ # otherwise the request forgery protection fails. It's only really necessary
+ # when you cross quarantine (logged-out to logged-in).
+ def logout_killing_session!
+ logout_keeping_session!
+ reset_session
+ end
+
+ #
+ # Remember_me Tokens
+ #
+ # Cookies shouldn't be allowed to persist past their freshness date,
+ # and they should be changed at each login
+
+ # Cookies shouldn't be allowed to persist past their freshness date,
+ # and they should be changed at each login
+
+ def valid_remember_cookie?
+ return nil unless @current_user
+ (@current_user.remember_token?) &&
+ (cookies[:auth_token] == @current_user.remember_token)
+ end
+
+ # Refresh the cookie auth token if it exists, create it otherwise
+ def handle_remember_cookie! new_cookie_flag
+ return unless @current_user
+ case
+ when valid_remember_cookie? then @current_user.refresh_token # keeping same expiry date
+ when new_cookie_flag then @current_user.remember_me
+ else @current_user.forget_me
+ end
+ send_remember_cookie!
+ end
+
+ def kill_remember_cookie!
+ cookies.delete :auth_token
+ end
+
+ def send_remember_cookie!
+ cookies[:auth_token] = {
+ :value => @current_user.remember_token,
+ :expires => @current_user.remember_token_expires_at }
+ end
+
+end
View
11 lib/authenticated_test_helper.rb
@@ -0,0 +1,11 @@
+module AuthenticatedTestHelper
+ # Sets the current user in the session from the user fixtures.
+ def login_as(user)
+ @request.session[:user_id] = user ? users(user).id : nil
+ end
+
+ def authorize_as(user)
+ @request.env["HTTP_AUTHORIZATION"] = user ? ActionController::HttpAuthentication::Basic.encode_credentials(users(user).login, 'monkey') : nil
+ end
+
+end
View
2,299 log/development.log
2,299 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
0 log/production.log
No changes.
View
0 log/server.log
No changes.
View
0 log/test.log
No changes.
View
BIN public/.DS_Store
Binary file not shown.
View
30 public/404.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>The page you were looking for doesn't exist (404)</title>
+ <style type="text/css">
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+ div.dialog {
+ width: 25em;
+ padding: 0 4em;
+ margin: 4em auto 0 auto;
+ border: 1px solid #ccc;
+ border-right-color: #999;
+ border-bottom-color: #999;
+ }
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+ </style>
+</head>
+
+<body>
+ <!-- This file lives in public/404.html -->
+ <div class="dialog">
+ <h1>The page you were looking for doesn't exist.</h1>
+ <p>You may have mistyped the address or the page may have moved.</p>
+ </div>
+</body>
+</html>
View
30 public/422.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>The change you wanted was rejected (422)</title>
+ <style type="text/css">
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+ div.dialog {
+ width: 25em;
+ padding: 0 4em;
+ margin: 4em auto 0 auto;
+ border: 1px solid #ccc;
+ border-right-color: #999;
+ border-bottom-color: #999;
+ }
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+ </style>
+</head>
+
+<body>
+ <!-- This file lives in public/422.html -->
+ <div class="dialog">
+ <h1>The change you wanted was rejected.</h1>
+ <p>Maybe you tried to change something you didn't have access to.</p>
+ </div>
+</body>
+</html>
View
30 public/500.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>We're sorry, but something went wrong (500)</title>
+ <style type="text/css">
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+ div.dialog {
+ width: 25em;
+ padding: 0 4em;
+ margin: 4em auto 0 auto;
+ border: 1px solid #ccc;
+ border-right-color: #999;
+ border-bottom-color: #999;
+ }
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+ </style>
+</head>
+
+<body>
+ <!-- This file lives in public/500.html -->
+ <div class="dialog">
+ <h1>We're sorry, but something went wrong.</h1>
+ <p>We've been notified about this issue and we'll take a look at it shortly.</p>
+ </div>
+</body>
+</html>
View
BIN public/assets/.DS_Store
Binary file not shown.
View
10 public/dispatch.cgi
@@ -0,0 +1,10 @@
+#!/opt/local/bin/ruby
+
+require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
+
+# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
+# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
+require "dispatcher"
+
+ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
+Dispatcher.dispatch
View
24 public/dispatch.fcgi
@@ -0,0 +1,24 @@
+#!/opt/local/bin/ruby
+#
+# You may specify the path to the FastCGI crash log (a log of unhandled
+# exceptions which forced the FastCGI instance to exit, great for debugging)
+# and the number of requests to process before running garbage collection.
+#
+# By default, the FastCGI crash log is RAILS_ROOT/log/fastcgi.crash.log
+# and the GC period is nil (turned off). A reasonable number of requests
+# could range from 10-100 depending on the memory footprint of your app.
+#
+# Example:
+# # Default log path, normal GC behavior.
+# RailsFCGIHandler.process!
+#
+# # Default log path, 50 requests between GC.
+# RailsFCGIHandler.process! nil, 50
+#
+# # Custom log path, normal GC behavior.
+# RailsFCGIHandler.process! '/var/log/myapp_fcgi_crash.log'
+#
+require File.dirname(__FILE__) + "/../config/environment"
+require 'fcgi_handler'
+
+RailsFCGIHandler.process!
View
10 public/dispatch.rb
@@ -0,0 +1,10 @@
+#!/opt/local/bin/ruby
+
+require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
+
+# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
+# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
+require "dispatcher"
+
+ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
+Dispatcher.dispatch
View
0 public/favicon.ico
No changes.
View
BIN public/flash/swfupload_f9.swf
Binary file not shown.
View
BIN public/images/.DS_Store
Binary file not shown.
View
BIN public/javascripts/.DS_Store
Binary file not shown.
View
755 public/javascripts/swfupload.js
@@ -0,0 +1,755 @@
+/**
+ * SWFUpload v2.1.0 by Jacob Roberts, Feb 2008, http://www.swfupload.org, http://swfupload.googlecode.com, http://www.swfupload.org
+ * -------- -------- -------- -------- -------- -------- -------- --------
+ * SWFUpload is (c) 2006 Lars Huring, Olov Nilzén and Mammon Media and is released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * See Changelog.txt for version history
+ *
+ */
+
+
+/* *********** */
+/* Constructor */
+/* *********** */
+
+var SWFUpload = function (settings) {
+ this.initSWFUpload(settings);
+};
+
+SWFUpload.prototype.initSWFUpload = function (settings) {
+ try {
+ this.customSettings = {}; // A container where developers can place their own settings associated with this instance.
+ this.settings = settings;
+ this.eventQueue = [];
+ this.movieName = "SWFUpload_" + SWFUpload.movieCount++;
+ this.movieElement = null;
+
+ // Setup global control tracking
+ SWFUpload.instances[this.movieName] = this;
+
+ // Load the settings. Load the Flash movie.
+ this.initSettings();
+ this.loadFlash();
+ this.displayDebugInfo();
+ } catch (ex) {
+ delete SWFUpload.instances[this.movieName];
+ throw ex;
+ }
+};
+
+/* *************** */
+/* Static Members */
+/* *************** */
+SWFUpload.instances = {};
+SWFUpload.movieCount = 0;
+SWFUpload.version = "2.1.0";
+SWFUpload.QUEUE_ERROR = {
+ QUEUE_LIMIT_EXCEEDED : -100,
+ FILE_EXCEEDS_SIZE_LIMIT : -110,
+ ZERO_BYTE_FILE : -120,
+ INVALID_FILETYPE : -130
+};
+SWFUpload.UPLOAD_ERROR = {
+ HTTP_ERROR : -200,
+ MISSING_UPLOAD_URL : -210,
+ IO_ERROR : -220,
+ SECURITY_ERROR : -230,
+ UPLOAD_LIMIT_EXCEEDED : -240,
+ UPLOAD_FAILED : -250,
+ SPECIFIED_FILE_ID_NOT_FOUND : -260,
+ FILE_VALIDATION_FAILED : -270,
+ FILE_CANCELLED : -280,
+ UPLOAD_STOPPED : -290
+};
+SWFUpload.FILE_STATUS = {
+ QUEUED : -1,
+ IN_PROGRESS : -2,
+ ERROR : -3,
+ COMPLETE : -4,
+ CANCELLED : -5
+};
+
+
+/* ******************** */
+/* Instance Members */
+/* ******************** */
+
+// Private: initSettings ensures that all the
+// settings are set, getting a default value if one was not assigned.
+SWFUpload.prototype.initSettings = function () {
+ this.ensureDefault = function (settingName, defaultValue) {
+ this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName];
+ };
+
+ // Upload backend settings
+ this.ensureDefault("upload_url", "");
+ this.ensureDefault("file_post_name", "Filedata");
+ this.ensureDefault("post_params", {});
+ this.ensureDefault("use_query_string", false);
+ this.ensureDefault("requeue_on_error", false);
+
+ // File Settings
+ this.ensureDefault("file_types", "*.*");
+ this.ensureDefault("file_types_description", "All Files");
+ this.ensureDefault("file_size_limit", 0); // Default zero means "unlimited"
+ this.ensureDefault("file_upload_limit", 0);
+ this.ensureDefault("file_queue_limit", 0);
+
+ // Flash Settings
+ this.ensureDefault("flash_url", "swfupload_f9.swf");
+ this.ensureDefault("flash_color", "#FFFFFF");
+
+ // Debug Settings
+ this.ensureDefault("debug", false);
+ this.settings.debug_enabled = this.settings.debug; // Here to maintain v2 API
+
+ // Event Handlers
+ this.settings.return_upload_start_handler = this.returnUploadStart;
+ this.ensureDefault("swfupload_loaded_handler", null);
+ this.ensureDefault("file_dialog_start_handler", null);
+ this.ensureDefault("file_queued_handler", null);
+ this.ensureDefault("file_queue_error_handler", null);
+ this.ensureDefault("file_dialog_complete_handler", null);
+
+ this.ensureDefault("upload_start_handler", null);
+ this.ensureDefault("upload_progress_handler", null);
+ this.ensureDefault("upload_error_handler", null);
+ this.ensureDefault("upload_success_handler", null);
+ this.ensureDefault("upload_complete_handler", null);
+
+ this.ensureDefault("debug_handler", this.debugMessage);
+
+ this.ensureDefault("custom_settings", {});
+
+ // Other settings
+ this.customSettings = this.settings.custom_settings;
+
+ delete this.ensureDefault;
+};
+
+// Private: loadFlash generates the HTML tag for the Flash
+// It then adds the flash to the body
+SWFUpload.prototype.loadFlash = function () {
+ var targetElement, container;
+
+ // Make sure an element with the ID we are going to use doesn't already exist
+ if (document.getElementById(this.movieName) !== null) {
+ throw "ID " + this.movieName + " is already in use. The Flash Object could not be added";
+ }
+
+ // Get the body tag where we will be adding the flash movie
+ targetElement = document.getElementsByTagName("body")[0];
+
+ if (targetElement == undefined) {
+ throw "Could not find the 'body' element.";
+ }
+
+ // Append the container and load the flash
+ container = document.createElement("div");
+ container.style.width = "1px";
+ container.style.height = "1px";
+
+ targetElement.appendChild(container);
+ container.innerHTML = this.getFlashHTML(); // Using innerHTML is non-standard but the only sensible way to dynamically add Flash in IE (and maybe other browsers)
+};
+
+// Private: getFlashHTML generates the object tag needed to embed the flash in to the document
+SWFUpload.prototype.getFlashHTML = function () {
+ // Flash Satay object syntax: http://www.alistapart.com/articles/flashsatay
+ return ['<object id="', this.movieName, '" type="application/x-shockwave-flash" data="', this.settings.flash_url, '" width="1" height="1" style="-moz-user-focus: ignore;">',
+ '<param name="movie" value="', this.settings.flash_url, '" />',
+ '<param name="bgcolor" value="', this.settings.flash_color, '" />',
+ '<param name="quality" value="high" />',
+ '<param name="menu" value="false" />',
+ '<param name="allowScriptAccess" value="always" />',
+ '<param name="flashvars" value="' + this.getFlashVars() + '" />',
+ '</object>'].join("");
+};
+
+// Private: getFlashVars builds the parameter string that will be passed
+// to flash in the flashvars param.
+SWFUpload.prototype.getFlashVars = function () {
+ // Build a string from the post param object
+ var paramString = this.buildParamString();
+
+ // Build the parameter string
+ return ["movieName=", encodeURIComponent(this.movieName),
+ "&amp;uploadURL=", encodeURIComponent(this.settings.upload_url),
+ "&amp;useQueryString=", encodeURIComponent(this.settings.use_query_string),
+ "&amp;requeueOnError=", encodeURIComponent(this.settings.requeue_on_error),
+ "&amp;params=", encodeURIComponent(paramString),
+ "&amp;filePostName=", encodeURIComponent(this.settings.file_post_name),
+ "&amp;fileTypes=", encodeURIComponent(this.settings.file_types),
+ "&amp;fileTypesDescription=", encodeURIComponent(this.settings.file_types_description),
+ "&amp;fileSizeLimit=", encodeURIComponent(this.settings.file_size_limit),
+ "&amp;fileUploadLimit=", encodeURIComponent(this.settings.file_upload_limit),
+ "&amp;fileQueueLimit=", encodeURIComponent(this.settings.file_queue_limit),
+ "&amp;debugEnabled=", encodeURIComponent(this.settings.debug_enabled)].join("");
+};
+
+// Public: getMovieElement retrieves the DOM reference to the Flash element added by SWFUpload
+// The element is cached after the first lookup
+SWFUpload.prototype.getMovieElement = function () {
+ if (this.movieElement == undefined) {
+ this.movieElement = document.getElementById(this.movieName);
+ }
+
+ if (this.movieElement === null) {
+ throw "Could not find Flash element";
+ }
+
+ return this.movieElement;
+};
+
+// Private: buildParamString takes the name/value pairs in the post_params setting object
+// and joins them up in to a string formatted "name=value&amp;name=value"
+SWFUpload.prototype.buildParamString = function () {
+ var postParams = this.settings.post_params;
+ var paramStringPairs = [];
+
+ if (typeof(postParams) === "object") {
+ for (var name in postParams) {
+ if (postParams.hasOwnProperty(name)) {
+ paramStringPairs.push(encodeURIComponent(name.toString()) + "=" + encodeURIComponent(postParams[name].toString()));
+ }
+ }
+ }
+
+ return paramStringPairs.join("&amp;");
+};
+
+// Public: Used to remove a SWFUpload instance from the page. This method strives to remove
+// all references to the SWF, and other objects so memory is properly freed.
+// Returns true if everything was destroyed. Returns a false if a failure occurs leaving SWFUpload in an inconsistant state.
+SWFUpload.prototype.destroy = function () {
+ try {
+ // Make sure Flash is done before we try to remove it
+ this.stopUpload();
+
+ // Remove the SWFUpload DOM nodes
+ var movieElement = null;
+ try {
+ movieElement = this.getMovieElement();
+ } catch (ex) {
+ }
+
+ if (movieElement != undefined && movieElement.parentNode != undefined && typeof(movieElement.parentNode.removeChild) === "function") {
+ var container = movieElement.parentNode;
+ if (container != undefined) {
+ container.removeChild(movieElement);
+ if (container.parentNode != undefined && typeof(container.parentNode.removeChild) === "function") {
+ container.parentNode.removeChild(container);
+ }
+ }
+ }
+
+ // Destroy references
+ SWFUpload.instances[this.movieName] = null;
+ delete SWFUpload.instances[this.movieName];
+
+ delete this.movieElement;
+ delete this.settings;
+ delete this.customSettings;
+ delete this.eventQueue;
+ delete this.movieName;
+
+ return true;
+ } catch (ex1) {
+ return false;
+ }
+};
+
+// Public: displayDebugInfo prints out settings and configuration
+// information about this SWFUpload instance.
+// This function (and any references to it) can be deleted when placing
+// SWFUpload in production.
+SWFUpload.prototype.displayDebugInfo = function () {
+ this.debug(
+ [
+ "---SWFUpload Instance Info---\n",
+ "Version: ", SWFUpload.version, "\n",
+ "Movie Name: ", this.movieName, "\n",
+ "Settings:\n",
+ "\t", "upload_url: ", this.settings.upload_url, "\n",
+ "\t", "use_query_string: ", this.settings.use_query_string.toString(), "\n",
+ "\t", "file_post_name: ", this.settings.file_post_name, "\n",
+ "\t", "post_params: ", this.settings.post_params.toString(), "\n",
+ "\t", "file_types: ", this.settings.file_types, "\n",
+ "\t", "file_types_description: ", this.settings.file_types_description, "\n",
+ "\t", "file_size_limit: ", this.settings.file_size_limit, "\n",
+ "\t", "file_upload_limit: ", this.settings.file_upload_limit, "\n",
+ "\t", "file_queue_limit: ", this.settings.file_queue_limit, "\n",
+ "\t", "flash_url: ", this.settings.flash_url, "\n",
+ "\t", "flash_color: ", this.settings.flash_color, "\n",
+ "\t", "debug: ", this.settings.debug.toString(), "\n",
+ "\t", "custom_settings: ", this.settings.custom_settings.toString(), "\n",
+ "Event Handlers:\n",
+ "\t", "swfupload_loaded_handler assigned: ", (typeof(this.settings.swfupload_loaded_handler) === "function").toString(), "\n",
+ "\t", "file_dialog_start_handler assigned: ", (typeof(this.settings.file_dialog_start_handler) === "function").toString(), "\n",
+ "\t", "file_queued_handler assigned: ", (typeof(this.settings.file_queued_handler) === "function").toString(), "\n",
+ "\t", "file_queue_error_handler assigned: ", (typeof(this.settings.file_queue_error_handler) === "function").toString(), "\n",
+ "\t", "upload_start_handler assigned: ", (typeof(this.settings.upload_start_handler) === "function").toString(), "\n",
+ "\t", "upload_progress_handler assigned: ", (typeof(this.settings.upload_progress_handler) === "function").toString(), "\n",
+ "\t", "upload_error_handler assigned: ", (typeof(this.settings.upload_error_handler) === "function").toString(), "\n",
+ "\t", "upload_success_handler assigned: ", (typeof(this.settings.upload_success_handler) === "function").toString(), "\n",
+ "\t", "upload_complete_handler assigned: ", (typeof(this.settings.upload_complete_handler) === "function").toString(), "\n",
+ "\t", "debug_handler assigned: ", (typeof(this.settings.debug_handler) === "function").toString(), "\n"
+ ].join("")
+ );
+};
+
+/* Note: addSetting and getSetting are no longer used by SWFUpload but are included
+ the maintain v2 API compatibility
+*/
+// Public: (Deprecated) addSetting adds a setting value. If the value given is undefined or null then the default_value is used.
+SWFUpload.prototype.addSetting = function (name, value, default_value) {
+ if (value == undefined) {
+ return (this.settings[name] = default_value);
+ } else {
+ return (this.settings[name] = value);
+ }
+};
+
+// Public: (Deprecated) getSetting gets a setting. Returns an empty string if the setting was not found.
+SWFUpload.prototype.getSetting = function (name) {
+ if (this.settings[name] != undefined) {
+ return this.settings[name];
+ }
+
+ return "";
+};
+
+
+
+// Private: callFlash handles function calls made to the Flash element.
+// Calls are made with a setTimeout for some functions to work around
+// bugs in the ExternalInterface library.
+SWFUpload.prototype.callFlash = function (functionName, argumentArray) {
+ argumentArray = argumentArray || [];
+
+ var self = this;
+ var callFunction = function () {
+ var movieElement = self.getMovieElement();
+ var returnValue;
+ if (typeof(movieElement[functionName]) === "function") {
+ // We have to go through all this if/else stuff because the Flash functions don't have apply() and only accept the exact number of arguments.
+ if (argumentArray.length === 0) {
+ returnValue = movieElement[functionName]();
+ } else if (argumentArray.length === 1) {
+ returnValue = movieElement[functionName](argumentArray[0]);
+ } else if (argumentArray.length === 2) {
+ returnValue = movieElement[functionName](argumentArray[0], argumentArray[1]);
+ } else if (argumentArray.length === 3) {
+ returnValue = movieElement[functionName](argumentArray[0], argumentArray[1], argumentArray[2]);
+ } else {
+ throw "Too many arguments";
+ }
+
+ // Unescape file post param values
+ if (returnValue != undefined && typeof(returnValue.post) === "object") {
+ returnValue = self.unescapeFilePostParams(returnValue);
+ }
+
+ return returnValue;
+ } else {
+ throw "Invalid function name";
+ }
+ };
+
+ return callFunction();
+};
+
+
+/* *****************************
+ -- Flash control methods --
+ Your UI should use these
+ to operate SWFUpload
+ ***************************** */
+
+// Public: selectFile causes a File Selection Dialog window to appear. This
+// dialog only allows 1 file to be selected.
+SWFUpload.prototype.selectFile = function () {
+ this.callFlash("SelectFile");
+};
+
+// Public: selectFiles causes a File Selection Dialog window to appear/ This
+// dialog allows the user to select any number of files
+// Flash Bug Warning: Flash limits the number of selectable files based on the combined length of the file names.
+// If the selection name length is too long the dialog will fail in an unpredictable manner. There is no work-around
+// for this bug.
+SWFUpload.prototype.selectFiles = function () {
+ this.callFlash("SelectFiles");
+};
+
+
+// Public: startUpload starts uploading the first file in the queue unless
+// the optional parameter 'fileID' specifies the ID
+SWFUpload.prototype.startUpload = function (fileID) {
+ this.callFlash("StartUpload", [fileID]);
+};
+
+/* Cancels a the file upload. You must specify a file_id */
+// Public: cancelUpload cancels any queued file. The fileID parameter
+// must be specified.
+SWFUpload.prototype.cancelUpload = function (fileID) {
+ this.callFlash("CancelUpload", [fileID]);
+};
+
+// Public: stopUpload stops the current upload and requeues the file at the beginning of the queue.
+// If nothing is currently uploading then nothing happens.
+SWFUpload.prototype.stopUpload = function () {
+ this.callFlash("StopUpload");
+};
+
+/* ************************
+ * Settings methods
+ * These methods change the SWFUpload settings.
+ * SWFUpload settings should not be changed directly on the settings object
+ * since many of the settings need to be passed to Flash in order to take
+ * effect.
+ * *********************** */
+
+// Public: getStats gets the file statistics object.
+SWFUpload.prototype.getStats = function () {
+ return this.callFlash("GetStats");
+};
+
+// Public: setStats changes the SWFUpload statistics. You shouldn't need to
+// change the statistics but you can. Changing the statistics does not
+// affect SWFUpload accept for the successful_uploads count which is used
+// by the upload_limit setting to determine how many files the user may upload.
+SWFUpload.prototype.setStats = function (statsObject) {
+ this.callFlash("SetStats", [statsObject]);
+};
+
+// Public: getFile retrieves a File object by ID or Index. If the file is
+// not found then 'null' is returned.
+SWFUpload.prototype.getFile = function (fileID) {
+ if (typeof(fileID) === "number") {
+ return this.callFlash("GetFileByIndex", [fileID]);
+ } else {