[38302] branches/gsoc08-mpwa

digx at macports.org digx at macports.org
Mon Jul 14 21:48:51 PDT 2008


Revision: 38302
          http://trac.macosforge.org/projects/macports/changeset/38302
Author:   digx at macports.org
Date:     2008-07-14 21:48:51 -0700 (Mon, 14 Jul 2008)
Log Message:
-----------
Plugins\!

Modified Paths:
--------------
    branches/gsoc08-mpwa/Rakefile

Added Paths:
-----------
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/.gitignore
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/CHANGELOG
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/MIT-LICENSE
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/README
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/acts-as-taggable-on.gemspec
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/generators/
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/generators/acts_as_taggable_on_migration/
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/generators/acts_as_taggable_on_migration/templates/
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/generators/acts_as_taggable_on_migration/templates/migration.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/init.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts-as-taggable-on.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/acts_as_taggable_on.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/acts_as_tagger.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tag.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tag_list.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tagging.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tags_helper.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/autotest/
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/autotest/discover.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/rails/
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/rails/init.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/acts_as_tagger_spec.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tag_list_spec.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tag_spec.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/taggable_spec.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tagger_spec.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tagging_spec.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/schema.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/spec.opts
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/spec_helper.rb
    branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/uninstall.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/.gitignore
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/CHANGELOG
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/README
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/Rakefile
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/TODO
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/USAGE
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/authenticated_generator.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/lib/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/lib/insert_routes.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/_model_partial.html.erb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/activation.html.erb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/authenticated_system.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/authenticated_test_helper.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/controller.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/helper.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/login.html.erb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/mailer.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/migration.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model_controller.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model_helper.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model_helper_spec.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/observer.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/signup.html.erb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/signup_notification.html.erb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/site_keys.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/access_control_spec.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/authenticated_system_spec.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/sessions_controller_spec.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/users_controller_spec.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/fixtures/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/fixtures/users.yml
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/helpers/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/helpers/users_helper_spec.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/models/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/models/user_spec.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/rest_auth_stories.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/rest_auth_stories_helper.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/ra_navigation_steps.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/ra_resource_steps.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/ra_response_steps.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/user_steps.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/users/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/users/accounts.story
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/users/sessions.story
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/functional_test.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/mailer_test.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/model_functional_test.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/unit_test.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/init.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/install.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authentication/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authentication/by_cookie_token.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authentication/by_password.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authentication.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authorization/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authorization/aasm_roles.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authorization/stateful_roles.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authorization.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/trustification/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/trustification/email_validation.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/trustification.rb
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/AccessControl.txt
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Authentication.txt
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Authorization.txt
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/RailsPlugins.txt
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/SecurityFramework.graffle
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/SecurityFramework.png
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/SecurityPatterns.txt
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Tradeoffs.txt
    branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Trustification.txt

Modified: branches/gsoc08-mpwa/Rakefile
===================================================================
--- branches/gsoc08-mpwa/Rakefile	2008-07-15 04:48:12 UTC (rev 38301)
+++ branches/gsoc08-mpwa/Rakefile	2008-07-15 04:48:51 UTC (rev 38302)
@@ -10,8 +10,7 @@
 require 'tasks/rails'
 
 begin
-  require 'vlad'
-  Vlad.load
+  require 'config/deploy'
 rescue LoadError
   # do nothing
 end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/.gitignore
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/.gitignore	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/.gitignore	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1 @@
+*.log
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/CHANGELOG
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/CHANGELOG	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/CHANGELOG	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,14 @@
+== 2008-06-23
+
+* Can now find related objects of another class (tristanzdunn)
+* Removed extraneous down migration cruft (azabaj)
+
+== 2008-06-09
+ 
+ * Added support for Single Table Inheritance
+ * Adding gemspec and rails/init.rb for gemified plugin
+ 
+== 2007-12-12
+
+ * Added ability to use dynamic tag contexts
+ * Fixed missing migration generator
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/MIT-LICENSE
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/MIT-LICENSE	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/MIT-LICENSE	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,20 @@
+Copyright (c) 2007 Michael Bleigh and Intridea Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/README
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/README	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/README	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,170 @@
+ActsAsTaggableOn
+================
+
+This plugin was originally based on Acts as Taggable on Steroids by Jonathan Viney.
+It has evolved substantially since that point, but all credit goes to him for the
+initial tagging functionality that so many people have used.
+
+For instance, in a social network, a user might have tags that are called skills,
+interests, sports, and more. There is no real way to differentiate between tags and
+so an implementation of this type is not possible with acts as taggable on steroids.
+
+Enter Acts as Taggable On. Rather than tying functionality to a specific keyword
+(namely "tags"), acts as taggable on allows you to specify an arbitrary number of
+tag "contexts" that can be used locally or in combination in the same way steroids
+was used.
+
+Installation
+============
+
+Plugin
+------
+
+Acts As Taggable On is available both as a gem and as a traditional plugin. For the
+traditional plugin you can install like so (Rails 2.1 or later):
+
+  script/plugin install git://github.com/mbleigh/acts-as-taggable-on.git
+  
+For earlier versions:
+
+  git clone git://github.com/mbleigh/acts-as-taggable-on.git vendor/plugins/acts-as-taggable-on
+  
+GemPlugin
+---------
+
+Acts As Taggable On is also available as a gem plugin using Rails 2.1's gem dependencies.
+To install the gem, add this to your config/environment.rb:
+  
+  config.gem "mbleigh-acts-as-taggable-on", :source => "http://gems.github.com", :lib => "acts-as-taggable-on"
+  
+After that, you can run "rake gems:install" to install the gem if you don't already have it.
+See http://ryandaigle.com/articles/2008/4/1/what-s-new-in-edge-rails-gem-dependencies for
+additional details about gem dependencies in Rails.
+
+** NOTE **
+Some issues have been experienced with "rake gems:install". If that doesn't work to install the gem,
+try just installing it as a normal gem:
+
+  gem install mbleigh-acts-as-taggable-on --source http://gems.github.com
+
+Post Installation (Rails)
+-------------------------
+1. script/generate acts_as_taggable_on_migration
+2. rake db/migrate
+
+Testing
+=======
+
+Acts As Taggable On uses RSpec for its test coverage. If you already have RSpec on your
+application, the specs will run while using:
+
+rake spec:plugins
+
+Example
+=======
+
+class User < ActiveRecord::Base
+  acts_as_taggable_on :tags, :skills, :interests
+end
+
+ at user = User.new(:name => "Bobby")
+ at user.tag_list = "awesome, slick, hefty"      # this should be familiar
+ at user.skill_list = "joking, clowning, boxing" # but you can do it for any context!
+ at user.skill_list # => ["joking","clowning","boxing"] as TagList
+ at user.save
+
+ at user.tags # => [<Tag name:"awesome">,<Tag name:"slick">,<Tag name:"hefty">]
+ at user.skills # => [<Tag name:"joking">,<Tag name:"clowning">,<Tag name:"boxing">]
+
+User.find_tagged_with("awesome", :on => :tags) # => [@user]
+User.find_tagged_with("awesome", :on => :skills) # => []
+
+ at frankie = User.create(:name => "Frankie", :skill_list => "joking, flying, eating")
+User.skill_counts # => [<Tag name="joking" count=2>,<Tag name="clowning" count=1>...]
+ at frankie.skill_counts
+
+Relationships
+====================
+
+You can find objects of the same type based on similar tags on certain contexts.
+Also, objects will be returned in descending order based on the total number of 
+matched tags.
+
+ at bobby = User.find_by_name("Bobby")
+ at bobby.skill_list # => ["jogging", "diving"]
+
+ at frankie = User.find_by_name("Frankie")
+ at frankie.skill_list # => ["hacking"]
+
+ at tom = User.find_by_name("Tom")
+ at tom.skill_list # => ["hacking", "jogging", "diving"]
+
+ at tom.find_related_skills # => [<User name="Bobby">,<User name="Frankie">]
+ at bobby.find_related_skills # => [<User name="Tom">] 
+ at frankie.find_related_skills # => [<User name="Tom">] 
+
+
+Dynamic Tag Contexts
+====================
+
+In addition to the generated tag contexts in the definition, it is also possible
+to allow for dynamic tag contexts (this could be user generated tag contexts!)
+
+ at user = User.new(:name => "Bobby")
+ at user.set_tag_list_on(:customs, "same, as, tag, list")
+ at user.tag_list_on(:customs) # => ["same","as","tag","list"]
+ at user.save
+ at user.tags_on(:customs) # => [<Tag name='same'>,...]
+ at user.tag_counts_on(:customs)
+User.find_tagged_with("same", :on => :customs) # => [@user]
+
+Tag Ownership
+=============
+
+Tags can have owners:
+
+class User < ActiveRecord::Base
+  acts_as_tagger
+end
+
+class Photo < ActiveRecord::Base
+  acts_as_taggable_on :locations
+end
+
+ at some_user.tag(@some_photo, :with => "paris, normandy", :on => :locations)
+ at some_user.owned_taggings
+ at some_user.owned_tags
+ at some_photo.locations_from(@some_user)
+
+Caveats, Uncharted Waters
+=========================
+
+This plugin is still under active development. Tag caching has not 
+been thoroughly (or even casually) tested and may not work as expected.
+
+Contributors
+============
+
+* Michael Bleigh - Original Author
+* Brendan Lim - Related Objects
+* Pradeep Elankumaran - Taggers
+* Sinclair Bain - Patch King
+
+Patch Contributors
+------------------
+
+* tristanzdunn - Related objects of other classes
+* azabaj - Fixed migrate down
+* Peter Cooper - named_scope fix
+* slainer68 - STI fix
+* harrylove - migration instructions and fix-ups
+* lawrencepit - cached tag work
+
+Resources
+=========
+
+* Acts As Community - http://www.actsascommunity.com/projects/acts-as-taggable-on
+* GitHub - http://github.com/mbleigh/acts-as-taggable-on
+* Lighthouse - http://mbleigh.lighthouseapp.com/projects/10116-acts-as-taggable-on
+
+Copyright (c) 2007 Michael Bleigh (http://mbleigh.com/) and Intridea Inc. (http://intridea.com/), released under the MIT license

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/acts-as-taggable-on.gemspec
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/acts-as-taggable-on.gemspec	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/acts-as-taggable-on.gemspec	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,42 @@
+Gem::Specification.new do |s|
+  s.name = "acts-as-taggable-on"
+  s.version = "1.0.1"
+  s.date = "2008-06-10"
+  s.summary = "Tagging for ActiveRecord with custom contexts and advanced features."
+  s.email = "michael at intridea.com"
+  s.homepage = "http://www.actsascommunity.com/projects/acts-as-taggable-on"
+  s.description = "Acts As Taggable On provides the ability to have multiple tag contexts on a single model in ActiveRecord. It also has support for tag clouds, related items, taggers, and more."
+  s.has_rdoc = false
+  s.authors = ["Michael Bleigh"]
+  s.files = [ "CHANGELOG",
+              "MIT-LICENSE",
+              "README",
+              "generators/acts_as_taggable_on_migration",
+              "generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb",
+              "generators/acts_as_taggable_on_migration/templates",
+              "generators/acts_as_taggable_on_migration/templates/add_users_migration.rb",
+              "generators/acts_as_taggable_on_migration/templates/migration.rb",
+              "init.rb",
+              "lib/acts-as-taggable-on.rb",
+              "lib/acts_as_taggable_on/acts_as_taggable_on.rb",
+              "lib/acts_as_taggable_on/acts_as_tagger.rb",
+              "lib/acts_as_taggable_on/tag.rb",
+              "lib/acts_as_taggable_on/tag_list.rb",
+              "lib/acts_as_taggable_on/tagging.rb",
+              "lib/acts_as_taggable_on/tags_helper.rb",
+              "rails/init.rb",
+              "spec/acts_as_taggable_on",
+              "spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb",
+              "spec/acts_as_taggable_on/tag_list_spec.rb",
+              "spec/acts_as_taggable_on/tag_spec.rb",
+              "spec/acts_as_taggable_on/taggable_spec.rb",
+              "spec/acts_as_taggable_on/tagger_spec.rb",
+              "spec/acts_as_taggable_on/tagging_spec.rb",
+              "spec/debug.log",
+              "spec/schema.rb",
+              "spec/spec_helper.rb",
+              "uninstall.rb" ]
+  #s.rdoc_options = ["--main", "README.txt"]
+  #s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
+  #s.add_dependency("mbleigh-mash", [">= 0.0.5"])
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,7 @@
+class ActsAsTaggableOnMigrationGenerator < Rails::Generator::Base 
+  def manifest 
+    record do |m| 
+      m.migration_template 'migration.rb', 'db/migrate', :migration_file_name => "acts_as_taggable_on_migration"
+    end
+  end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/generators/acts_as_taggable_on_migration/templates/migration.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/generators/acts_as_taggable_on_migration/templates/migration.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/generators/acts_as_taggable_on_migration/templates/migration.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,29 @@
+class ActsAsTaggableOnMigration < ActiveRecord::Migration
+  def self.up
+    create_table :tags do |t|
+      t.column :name, :string
+    end
+    
+    create_table :taggings do |t|
+      t.column :tag_id, :integer
+      t.column :taggable_id, :integer
+      t.column :tagger_id, :integer
+      t.column :tagger_type, :string
+      
+      # You should make sure that the column created is
+      # long enough to store the required class names.
+      t.column :taggable_type, :string
+      t.column :context, :string
+      
+      t.column :created_at, :datetime
+    end
+    
+    add_index :taggings, :tag_id
+    add_index :taggings, [:taggable_id, :taggable_type, :context]
+  end
+  
+  def self.down
+    drop_table :taggings
+    drop_table :tags
+  end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/init.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/init.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/init.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1 @@
+require File.dirname(__FILE__) + "/rails/init"
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts-as-taggable-on.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts-as-taggable-on.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts-as-taggable-on.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,6 @@
+require 'acts_as_taggable_on/acts_as_taggable_on'
+require 'acts_as_taggable_on/acts_as_tagger'
+require 'acts_as_taggable_on/tag'
+require 'acts_as_taggable_on/tag_list'
+require 'acts_as_taggable_on/tags_helper'
+require 'acts_as_taggable_on/tagging'
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/acts_as_taggable_on.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/acts_as_taggable_on.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/acts_as_taggable_on.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,310 @@
+module ActiveRecord
+  module Acts
+    module TaggableOn
+      def self.included(base)
+        base.extend(ClassMethods)
+      end
+      
+      module ClassMethods
+        def taggable?
+          false
+        end
+        
+        def acts_as_taggable
+          acts_as_taggable_on :tags
+        end
+        
+        def acts_as_taggable_on(*args)
+          args.flatten! if args
+          args.compact! if args
+          for tag_type in args
+            tag_type = tag_type.to_s
+            self.class_eval do
+              has_many "#{tag_type.singularize}_taggings".to_sym, :as => :taggable, :dependent => :destroy, 
+                :include => :tag, :conditions => ["context = ?",tag_type], :class_name => "Tagging"
+              has_many "#{tag_type}".to_sym, :through => "#{tag_type.singularize}_taggings".to_sym, :source => :tag
+            end
+            
+            self.class_eval <<-RUBY
+              def self.taggable?
+                true
+              end
+              
+              def self.caching_#{tag_type.singularize}_list?
+                caching_tag_list_on?("#{tag_type}")
+              end
+              
+              def self.#{tag_type.singularize}_counts(options={})
+                tag_counts_on('#{tag_type}',options)
+              end
+        
+              def #{tag_type.singularize}_list
+                tag_list_on('#{tag_type}')
+              end
+            
+              def #{tag_type.singularize}_list=(new_tags)
+                set_tag_list_on('#{tag_type}',new_tags)
+              end
+            
+              def #{tag_type.singularize}_counts(options = {})
+                tag_counts_on('#{tag_type}',options)
+              end
+              
+              def #{tag_type}_from(owner)
+                tag_list_on('#{tag_type}', owner)
+              end
+              
+              def find_related_#{tag_type}(options = {})
+                related_tags_for('#{tag_type}', self.class, options)
+              end
+              alias_method :find_related_on_#{tag_type}, :find_related_#{tag_type}
+
+              def find_related_#{tag_type}_for(klass, options = {})
+                related_tags_for('#{tag_type}', klass, options)
+              end
+            RUBY
+          end      
+          
+          if respond_to?(:tag_types)
+            write_inheritable_attribute( :tag_types, (tag_types + args).uniq )
+          else
+            self.class_eval do
+              write_inheritable_attribute(:tag_types, args.uniq)
+              class_inheritable_reader :tag_types
+            
+              has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag
+              has_many :base_tags, :class_name => "Tag", :through => :taggings, :source => :tag
+            
+              attr_writer :custom_contexts
+            
+              before_save :save_cached_tag_list
+              after_save :save_tags
+            end
+            
+            include ActiveRecord::Acts::TaggableOn::InstanceMethods
+            extend ActiveRecord::Acts::TaggableOn::SingletonMethods                
+            alias_method_chain :reload, :tag_list
+          end
+        end
+        
+        def is_taggable?
+          false
+        end
+      end
+      
+      module SingletonMethods
+        # Pass either a tag string, or an array of strings or tags
+        # 
+        # Options:
+        #   :exclude - Find models that are not tagged with the given tags
+        #   :match_all - Find models that match all of the given tags, not just one
+        #   :conditions - A piece of SQL conditions to add to the query
+        #   :on - scopes the find to a context
+        def find_tagged_with(*args)
+          options = find_options_for_find_tagged_with(*args)
+          options.blank? ? [] : find(:all,options)
+        end
+        
+        def caching_tag_list_on?(context)
+          column_names.include?("cached_#{context.to_s.singularize}_list")
+        end     
+        
+        def tag_counts_on(context, options = {})
+          Tag.find(:all, find_options_for_tag_counts(options.merge({:on => context.to_s})))
+        end           
+        
+        def find_options_for_find_tagged_with(tags, options = {})
+          tags = tags.is_a?(Array) ? TagList.new(tags.map(&:to_s)) : TagList.from(tags)
+
+          return {} if tags.empty?
+
+          conditions = []
+          conditions << sanitize_sql(options.delete(:conditions)) if options[:conditions]
+          
+          unless (on = options.delete(:on)).nil?
+            conditions << sanitize_sql(["context = ?",on.to_s])
+          end
+
+          taggings_alias, tags_alias = "#{table_name}_taggings", "#{table_name}_tags"
+
+          if options.delete(:exclude)
+            tags_conditions = tags.map { |t| sanitize_sql(["#{Tag.table_name}.name LIKE ?", t]) }.join(" OR ")
+            conditions << sanitize_sql(["#{table_name}.id NOT IN (SELECT #{Tagging.table_name}.taggable_id FROM #{Tagging.table_name} LEFT OUTER JOIN #{Tag.table_name} ON #{Tagging.table_name}.tag_id = #{Tag.table_name}.id WHERE (#{tags_conditions}) AND #{Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})", tags])
+          else
+            conditions << tags.map { |t| sanitize_sql(["#{tags_alias}.name LIKE ?", t]) }.join(" OR ")
+
+            if options.delete(:match_all)
+              group = "#{taggings_alias}.taggable_id HAVING COUNT(#{taggings_alias}.taggable_id) = #{tags.size}"
+            end
+          end
+          
+          { :select => "DISTINCT #{table_name}.*",
+            :joins => "LEFT OUTER JOIN #{Tagging.table_name} #{taggings_alias} ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key} AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)} " +
+                      "LEFT OUTER JOIN #{Tag.table_name} #{tags_alias} ON #{tags_alias}.id = #{taggings_alias}.tag_id",
+            :conditions => conditions.join(" AND "),
+            :group      => group
+          }.update(options)
+        end    
+        
+        # Calculate the tag counts for all tags.
+        # 
+        # Options:
+        #  :start_at - Restrict the tags to those created after a certain time
+        #  :end_at - Restrict the tags to those created before a certain time
+        #  :conditions - A piece of SQL conditions to add to the query
+        #  :limit - The maximum number of tags to return
+        #  :order - A piece of SQL to order by. Eg 'tags.count desc' or 'taggings.created_at desc'
+        #  :at_least - Exclude tags with a frequency less than the given value
+        #  :at_most - Exclude tags with a frequency greater than the given value
+        #  :on - Scope the find to only include a certain context
+        def find_options_for_tag_counts(options = {})
+          options.assert_valid_keys :start_at, :end_at, :conditions, :at_least, :at_most, :order, :limit, :on
+          
+          scope = scope(:find)
+          start_at = sanitize_sql(["#{Tagging.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
+          end_at = sanitize_sql(["#{Tagging.table_name}.created_at <= ?", options.delete(:end_at)]) if options[:end_at]
+
+          type_and_context = "#{Tagging.table_name}.taggable_type = #{quote_value(base_class.name)}"
+          
+          conditions = [
+            type_and_context,
+            options[:conditions],
+            start_at,
+            end_at
+          ]
+
+          conditions = conditions.compact.join(' AND ')
+          conditions = merge_conditions(conditions, scope[:conditions]) if scope
+
+          joins = ["LEFT OUTER JOIN #{Tagging.table_name} ON #{Tag.table_name}.id = #{Tagging.table_name}.tag_id"]
+          joins << sanitize_sql(["AND #{Tagging.table_name}.context = ?",options.delete(:on).to_s]) unless options[:on].nil?
+          joins << "LEFT OUTER JOIN #{table_name} ON #{table_name}.#{primary_key} = #{Tagging.table_name}.taggable_id"
+          joins << scope[:joins] if scope && scope[:joins]
+
+          at_least  = sanitize_sql(['COUNT(*) >= ?', options.delete(:at_least)]) if options[:at_least]
+          at_most   = sanitize_sql(['COUNT(*) <= ?', options.delete(:at_most)]) if options[:at_most]
+          having    = [at_least, at_most].compact.join(' AND ')
+          group_by  = "#{Tag.table_name}.id, #{Tag.table_name}.name HAVING COUNT(*) > 0"
+          group_by << " AND #{having}" unless having.blank?
+
+          { :select     => "#{Tag.table_name}.id, #{Tag.table_name}.name, COUNT(*) AS count", 
+            :joins      => joins.join(" "),
+            :conditions => conditions,
+            :group      => group_by
+          }.update(options)
+        end    
+        
+        def is_taggable?
+          true
+        end                
+      end
+    
+      module InstanceMethods
+        
+        def tag_types
+          self.class.tag_types
+        end
+        
+        def custom_contexts
+          @custom_contexts ||= []
+        end
+        
+        def is_taggable?
+          self.class.is_taggable?
+        end
+        
+        def add_custom_context(value)
+          custom_contexts << value.to_s unless custom_contexts.include?(value.to_s) or self.class.tag_types.map(&:to_s).include?(value.to_s)
+        end
+        
+        def tag_list_on(context, owner=nil)
+          var_name = context.to_s.singularize + "_list"
+          add_custom_context(context)
+          return instance_variable_get("@#{var_name}") unless instance_variable_get("@#{var_name}").nil?
+        
+          if !owner && self.class.caching_tag_list_on?(context) and !(cached_value = cached_tag_list_on(context)).nil?
+            instance_variable_set("@#{var_name}", TagList.from(self["cached_#{var_name}"]))
+          else
+            instance_variable_set("@#{var_name}", TagList.new(*tags_on(context, owner).map(&:name)))
+          end
+        end
+        
+        def tags_on(context, owner=nil)
+          if owner
+            opts = {:conditions => ["context = ? AND tagger_id = ? AND tagger_type = ?",
+                                    context.to_s, owner.id, owner.class.to_s]}
+          else
+            opts = {:conditions => ["context = ?", context.to_s]}
+          end
+          base_tags.find(:all, opts)
+        end
+        
+        def cached_tag_list_on(context)
+          self["cached_#{context.to_s.singularize}_list"]
+        end
+        
+        def set_tag_list_on(context,new_list, tagger=nil)
+          instance_variable_set("@#{context.to_s.singularize}_list", TagList.from_owner(tagger, new_list))
+          add_custom_context(context)
+        end
+        
+        def tag_counts_on(context,options={})
+          self.class.tag_counts_on(context,{:conditions => ["#{Tag.table_name}.name IN (?)", tag_list_on(context)]}.reverse_merge!(options))
+        end
+
+        def related_tags_for(context, klass, options = {})
+          search_conditions = related_search_options(context, klass, options)
+
+          klass.find(:all, search_conditions)
+        end
+
+        def related_search_options(context, klass, options = {})
+          tags_to_find = self.tags_on(context).collect { |t| t.name }
+
+          { :select     => "#{klass.table_name}.*, COUNT(#{Tag.table_name}.id) AS count", 
+            :from       => "#{klass.table_name}, #{Tag.table_name}, #{Tagging.table_name}",
+            :conditions => ["#{klass.table_name}.id = #{Tagging.table_name}.taggable_id AND #{Tagging.table_name}.taggable_type = '#{klass.to_s}' AND #{Tagging.table_name}.tag_id = #{Tag.table_name}.id AND #{Tag.table_name}.name IN (?)", tags_to_find],
+            :group      => "#{klass.table_name}.id",
+            :order      => "count DESC"
+          }.update(options)
+        end
+        
+        def save_cached_tag_list
+          self.class.tag_types.map(&:to_s).each do |tag_type|
+            if self.class.send("caching_#{tag_type.singularize}_list?")
+              self["cached_#{tag_type.singularize}_list"] = send("#{tag_type.singularize}_list").to_s
+            end
+          end
+        end
+        
+        def save_tags
+          (custom_contexts + self.class.tag_types.map(&:to_s)).each do |tag_type|
+            next unless instance_variable_get("@#{tag_type.singularize}_list")
+            owner = instance_variable_get("@#{tag_type.singularize}_list").owner
+            new_tag_names = instance_variable_get("@#{tag_type.singularize}_list") - tags_on(tag_type).map(&:name)
+            old_tags = tags_on(tag_type).reject { |tag| instance_variable_get("@#{tag_type.singularize}_list").include?(tag.name) }
+          
+            self.class.transaction do
+              base_tags.delete(*old_tags) if old_tags.any?
+              new_tag_names.each do |new_tag_name|
+                new_tag = Tag.find_or_create_with_like_by_name(new_tag_name)
+                Tagging.create(:tag_id => new_tag.id, :context => tag_type, 
+                               :taggable => self, :tagger => owner)
+              end
+            end
+          end
+          
+          true
+        end
+        
+        def reload_with_tag_list(*args)
+          self.class.tag_types.each do |tag_type|
+            self.instance_variable_set("@#{tag_type.to_s.singularize}_list", nil)
+          end
+          
+          reload_without_tag_list(*args)
+        end
+      end
+    end
+  end
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/acts_as_tagger.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/acts_as_tagger.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/acts_as_tagger.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,52 @@
+module ActiveRecord
+  module Acts
+    module Tagger
+      def self.included(base)
+        base.extend ClassMethods
+      end
+      
+      module ClassMethods
+        def acts_as_tagger(opts={})
+          has_many :owned_taggings, opts.merge(:as => :tagger, :dependent => :destroy, 
+                                               :include => :tag, :class_name => "Tagging")
+          has_many :owned_tags, :through => :owned_taggings, :source => :tag
+          include ActiveRecord::Acts::Tagger::InstanceMethods
+          extend ActiveRecord::Acts::Tagger::SingletonMethods       
+        end
+        
+        def is_tagger?
+          false
+        end
+      end
+      
+      module InstanceMethods
+        def self.included(base)
+        end
+        
+        def tag(taggable, opts={})
+          opts.reverse_merge!(:force => true)
+
+          return false unless taggable.respond_to?(:is_taggable?) && taggable.is_taggable?
+          raise "You need to specify a tag context using :on" unless opts.has_key?(:on)
+          raise "You need to specify some tags using :with" unless opts.has_key?(:with)
+          raise "No context :#{opts[:on]} defined in #{taggable.class.to_s}" unless 
+              ( opts[:force] || taggable.tag_types.include?(opts[:on]) )
+
+          taggable.set_tag_list_on(opts[:on].to_s, opts[:with], self)
+          taggable.save
+        end
+        
+        def is_tagger?
+          self.class.is_tagger?
+        end
+      end
+      
+      module SingletonMethods
+        def is_tagger?
+          true
+        end
+      end
+      
+    end
+  end
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tag.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tag.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tag.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,23 @@
+class Tag < ActiveRecord::Base
+  has_many :taggings
+  
+  validates_presence_of :name
+  validates_uniqueness_of :name
+  
+  # LIKE is used for cross-database case-insensitivity
+  def self.find_or_create_with_like_by_name(name)
+    find(:first, :conditions => ["name LIKE ?", name]) || create(:name => name)
+  end
+  
+  def ==(object)
+    super || (object.is_a?(Tag) && name == object.name)
+  end
+  
+  def to_s
+    name
+  end
+  
+  def count
+    read_attribute(:count).to_i
+  end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tag_list.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tag_list.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tag_list.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,93 @@
+class TagList < Array
+  cattr_accessor :delimiter
+  self.delimiter = ','
+  
+  def initialize(*args)
+    add(*args)
+  end
+  
+  attr_accessor :owner
+  
+  # Add tags to the tag_list. Duplicate or blank tags will be ignored.
+  #
+  #   tag_list.add("Fun", "Happy")
+  # 
+  # Use the <tt>:parse</tt> option to add an unparsed tag string.
+  #
+  #   tag_list.add("Fun, Happy", :parse => true)
+  def add(*names)
+    extract_and_apply_options!(names)
+    concat(names)
+    clean!
+    self
+  end
+  
+  # Remove specific tags from the tag_list.
+  # 
+  #   tag_list.remove("Sad", "Lonely")
+  #
+  # Like #add, the <tt>:parse</tt> option can be used to remove multiple tags in a string.
+  # 
+  #   tag_list.remove("Sad, Lonely", :parse => true)
+  def remove(*names)
+    extract_and_apply_options!(names)
+    delete_if { |name| names.include?(name) }
+    self
+  end
+  
+  # Transform the tag_list into a tag string suitable for edting in a form.
+  # The tags are joined with <tt>TagList.delimiter</tt> and quoted if necessary.
+  #
+  #   tag_list = TagList.new("Round", "Square,Cube")
+  #   tag_list.to_s # 'Round, "Square,Cube"'
+  def to_s
+    clean!
+    
+    map do |name|
+      name.include?(delimiter) ? "\"#{name}\"" : name
+    end.join(delimiter.ends_with?(" ") ? delimiter : "#{delimiter} ")
+  end
+  
+ private
+  # Remove whitespace, duplicates, and blanks.
+  def clean!
+    reject!(&:blank?)
+    map!(&:strip)
+    uniq!
+  end
+  
+  def extract_and_apply_options!(args)
+    options = args.last.is_a?(Hash) ? args.pop : {}
+    options.assert_valid_keys :parse
+    
+    if options[:parse]
+      args.map! { |a| self.class.from(a) }
+    end
+    
+    args.flatten!
+  end
+  
+  class << self
+    # Returns a new TagList using the given tag string.
+    # 
+    #   tag_list = TagList.from("One , Two,  Three")
+    #   tag_list # ["One", "Two", "Three"]
+    def from(string)
+      returning new do |tag_list|
+        string = string.to_s.dup
+        
+        # Parse the quoted tags
+        string.gsub!(/"(.*?)"\s*#{delimiter}?\s*/) { tag_list << $1; "" }
+        string.gsub!(/'(.*?)'\s*#{delimiter}?\s*/) { tag_list << $1; "" }
+        
+        tag_list.add(string.split(delimiter))
+      end
+    end
+    
+    def from_owner(owner, *tags)
+      returning from(*tags) do |taglist|
+        taglist.owner = owner
+      end
+    end
+  end
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tagging.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tagging.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tagging.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,6 @@
+class Tagging < ActiveRecord::Base #:nodoc:
+  belongs_to :tag
+  belongs_to :taggable, :polymorphic => true
+  belongs_to :tagger, :polymorphic => true
+  validates_presence_of :context
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tags_helper.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tags_helper.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tags_helper.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,11 @@
+module TagsHelper
+  # See the README for an example using tag_cloud.
+  def tag_cloud(tags, classes)
+    max_count = tags.sort_by(&:count).last.count.to_f
+    
+    tags.each do |tag|
+      index = ((tag.count / max_count) * (classes.size - 1)).round
+      yield tag, classes[index]
+    end
+  end
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/autotest/discover.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/autotest/discover.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/lib/autotest/discover.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,6 @@
+# Need this to get picked up by autotest?
+$:.push(File.join(File.dirname(__FILE__), %w[.. .. rspec]))  
+   
+Autotest.add_discovery do  
+  "rspec" 
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/rails/init.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/rails/init.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/rails/init.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,6 @@
+require 'acts-as-taggable-on'
+
+ActiveRecord::Base.send :include, ActiveRecord::Acts::TaggableOn
+ActiveRecord::Base.send :include, ActiveRecord::Acts::Tagger
+
+RAILS_DEFAULT_LOGGER.info "** acts_as_taggable_on: initialized properly."
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,151 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe "Acts As Taggable On" do
+  it "should provide a class method 'taggable?' that is false for untaggable models" do
+    UntaggableModel.should_not be_taggable
+  end
+  
+  describe "Taggable Method Generation" do
+    before(:each) do
+      [TaggableModel, Tag, Tagging, TaggableUser].each(&:delete_all)
+      @taggable = TaggableModel.new(:name => "Bob Jones")
+    end
+  
+    it "should respond 'true' to taggable?" do
+      @taggable.class.should be_taggable
+    end
+    
+    it "should create a class attribute for tag types" do
+      @taggable.class.should respond_to(:tag_types)
+    end
+  
+    it "should generate an association for each tag type" do
+      @taggable.should respond_to(:tags, :skills, :languages)
+    end
+    
+    it "should generate a cached column checker for each tag type" do
+     TaggableModel.should respond_to(:caching_tag_list?, :caching_skill_list?, :caching_language_list?)
+    end
+    
+    it "should add tagged_with and tag_counts to singleton" do
+      TaggableModel.should respond_to(:find_tagged_with, :tag_counts)
+    end
+    
+    it "should add saving of tag lists and cached tag lists to the instance" do
+      @taggable.should respond_to(:save_cached_tag_list)
+      @taggable.should respond_to(:save_tags)
+    end
+  
+    it "should generate a tag_list accessor/setter for each tag type" do
+      @taggable.should respond_to(:tag_list, :skill_list, :language_list)
+      @taggable.should respond_to(:tag_list=, :skill_list=, :language_list=)
+    end
+  end
+  
+  describe "Single Table Inheritance" do
+    before do
+      @taggable = TaggableModel.new(:name => "taggable")
+      @inherited_same = InheritingTaggableModel.new(:name => "inherited same")
+      @inherited_different = AlteredInheritingTaggableModel.new(:name => "inherited different")
+    end
+    
+    it "should pass on tag contexts to STI-inherited models" do
+      @inherited_same.should respond_to(:tag_list, :skill_list, :language_list)
+      @inherited_different.should respond_to(:tag_list, :skill_list, :language_list)
+    end
+    
+    it "should have tag contexts added in altered STI models" do
+      @inherited_different.should respond_to(:part_list)
+    end
+  end
+  
+  describe "Reloading" do
+    it "should save a model instantiated by Model.find" do
+      taggable = TaggableModel.create!(:name => "Taggable")
+      found_taggable = TaggableModel.find(taggable.id)
+      found_taggable.save
+    end
+  end
+  
+  describe "Related Objects" do
+    it "should find related objects based on tag names on context" do
+      taggable1 = TaggableModel.create!(:name => "Taggable 1")
+      taggable2 = TaggableModel.create!(:name => "Taggable 2")
+      taggable3 = TaggableModel.create!(:name => "Taggable 3")
+
+      taggable1.tag_list = "one, two"
+      taggable1.save
+      
+      taggable2.tag_list = "three, four"
+      taggable2.save
+      
+      taggable3.tag_list = "one, four"
+      taggable3.save
+      
+      taggable1.find_related_tags.should include(taggable3)
+      taggable1.find_related_tags.should_not include(taggable2)
+    end
+
+    it "should find other related objects based on tag names on context" do
+      taggable1 = TaggableModel.create!(:name => "Taggable 1")
+      taggable2 = OtherTaggableModel.create!(:name => "Taggable 2")
+      taggable3 = OtherTaggableModel.create!(:name => "Taggable 3")
+
+      taggable1.tag_list = "one, two"
+      taggable1.save
+      
+      taggable2.tag_list = "three, four"
+      taggable2.save
+      
+      taggable3.tag_list = "one, four"
+      taggable3.save
+
+      taggable1.find_related_tags_for(OtherTaggableModel).should include(taggable3)
+      taggable1.find_related_tags_for(OtherTaggableModel).should_not include(taggable2)
+    end
+  end
+  
+  describe 'Tagging Contexts' do
+    before(:all) do
+      class Array
+        def freq
+          k=Hash.new(0)
+          self.each {|e| k[e]+=1}
+          k
+        end
+      end
+    end
+    
+    it 'should eliminate duplicate tagging contexts ' do
+      TaggableModel.acts_as_taggable_on(:skills, :skills)
+      TaggableModel.tag_types.freq[:skills].should_not == 3
+    end
+
+    it "should not contain embedded/nested arrays" do
+      TaggableModel.acts_as_taggable_on([:array], [:array])
+      TaggableModel.tag_types.freq[[:array]].should == 0
+    end
+
+    it "should _flatten_ the content of arrays" do
+      TaggableModel.acts_as_taggable_on([:array], [:array])
+      TaggableModel.tag_types.freq[:array].should == 1
+    end
+
+    it "should not raise an error when passed nil" do
+      lambda {
+        TaggableModel.acts_as_taggable_on()
+      }.should_not raise_error
+    end
+
+    it "should not raise an error when passed [nil]" do
+      lambda {
+        TaggableModel.acts_as_taggable_on([nil])
+      }.should_not raise_error
+    end
+
+    after(:all) do
+      class Array; remove_method :freq; end
+    end
+  end
+  
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/acts_as_tagger_spec.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/acts_as_tagger_spec.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/acts_as_tagger_spec.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,72 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe "acts_as_tagger" do
+  context "Tagger Method Generation" do
+
+    before(:each) do
+      @tagger = TaggableUser.new()
+    end
+
+    it "should add #is_tagger? query method to the class-side" do
+      TaggableUser.should respond_to(:is_tagger?)
+    end
+    
+    it "should return true from the class-side #is_tagger?" do
+      TaggableUser.is_tagger?.should be_true
+    end
+    
+    it "should return false from the base #is_tagger?" do
+      ActiveRecord::Base.is_tagger?.should be_false
+    end
+    
+    it "should add #is_tagger? query method to the singleton" do
+      @tagger.should respond_to(:is_tagger?)
+    end
+    
+    it "should add #tag method on the instance-side" do
+      @tagger.should respond_to(:tag)
+    end
+    
+    it "should generate an association for #owned_taggings and #owned_tags" do
+      @tagger.should respond_to(:owned_taggings, :owned_tags)
+    end
+  end
+  
+  describe "#tag" do
+    context 'when called with a non-existent tag context' do
+      before(:each) do
+        @tagger = TaggableUser.new()
+        @taggable = TaggableModel.new(:name=>"Richard Prior")
+      end
+      
+      it "should by default not throw an exception " do
+        @taggable.tag_list_on(:foo).should be_empty
+        lambda {
+          @tagger.tag(@taggable, :with=>'this, and, that', :on=>:foo)
+        }.should_not raise_error
+      end
+      
+      it 'should by default create the tag context on-the-fly' do
+        @taggable.tag_list_on(:here_ond_now).should be_empty
+        @tagger.tag(@taggable, :with=>'that', :on=>:here_ond_now)
+        @taggable.tag_list_on(:here_ond_now).should include('that')
+      end
+      
+      it "should throw an exception when the default is over-ridden" do
+        @taggable.tag_list_on(:foo_boo).should be_empty
+        lambda {
+          @tagger.tag(@taggable, :with=>'this, and, that', :on=>:foo_boo, :force=>false)
+        }.should raise_error        
+      end
+
+      it "should not create the tag context on-the-fly when the default is over-ridden" do
+        @taggable.tag_list_on(:foo_boo).should be_empty
+        @tagger.tag(@taggable, :with=>'this, and, that', :on=>:foo_boo, :force=>false) rescue
+        @taggable.tag_list_on(:foo_boo).should be_empty
+      end
+
+    end
+  
+  end
+
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tag_list_spec.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tag_list_spec.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tag_list_spec.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,41 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe TagList do
+  before(:each) do
+    @tag_list = TagList.new("awesome","radical")
+  end
+  
+  it "should be an array" do
+    @tag_list.is_a?(Array).should be_true
+  end
+  
+  it "should be able to be add a new tag word" do
+    @tag_list.add("cool")
+    @tag_list.include?("cool").should be_true
+  end
+  
+  it "should be able to add delimited lists of words" do
+    @tag_list.add("cool, wicked", :parse => true)
+    @tag_list.include?("cool").should be_true
+    @tag_list.include?("wicked").should be_true
+  end
+  
+  it "should be able to remove words" do
+    @tag_list.remove("awesome")
+    @tag_list.include?("awesome").should be_false
+  end
+  
+  it "should be able to remove delimited lists of words" do
+    @tag_list.remove("awesome, radical", :parse => true)
+    @tag_list.should be_empty
+  end
+  
+  it "should give a delimited list of words when converted to string" do
+    @tag_list.to_s.should == "awesome, radical"
+  end
+  
+  it "should quote escape tags with commas in them" do
+    @tag_list.add("cool","rad,bodacious")
+    @tag_list.to_s.should == "awesome, radical, cool, \"rad,bodacious\""
+  end
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tag_spec.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tag_spec.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tag_spec.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,25 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe Tag do
+  before(:each) do
+    @tag = Tag.new
+    @user = TaggableModel.create(:name => "Pablo")  
+  end
+  
+  it "should require a name" do
+    @tag.should have(1).errors_on(:name)
+    @tag.name = "something"
+    @tag.should have(0).errors_on(:name)    
+  end
+  
+  it "should equal a tag with the same name" do
+    @tag.name = "awesome"
+    new_tag = Tag.new(:name => "awesome")
+    new_tag.should == @tag
+  end
+  
+  it "should return its name when to_s is called" do
+    @tag.name = "cool"
+    @tag.to_s.should == "cool"
+  end
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/taggable_spec.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/taggable_spec.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/taggable_spec.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,127 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe "Taggable" do
+  before(:each) do
+    [TaggableModel, Tag, Tagging, TaggableUser].each(&:delete_all)
+    @taggable = TaggableModel.new(:name => "Bob Jones")
+  end
+  
+  it "should be able to create tags" do
+    @taggable.skill_list = "ruby, rails, css"
+    @taggable.instance_variable_get("@skill_list").instance_of?(TagList).should be_true
+    @taggable.save
+    
+    Tag.find(:all).size.should == 3
+  end
+  
+  it "should be able to create tags through the tag list directly" do
+    @taggable.tag_list_on(:test).add("hello")
+    @taggable.save    
+    @taggable.reload
+    @taggable.tag_list_on(:test).should == ["hello"]
+  end
+  
+  it "should differentiate between contexts" do
+    @taggable.skill_list = "ruby, rails, css"
+    @taggable.tag_list = "ruby, bob, charlie"
+    @taggable.save
+    @taggable.reload
+    @taggable.skill_list.include?("ruby").should be_true
+    @taggable.skill_list.include?("bob").should be_false
+  end
+  
+  it "should be able to remove tags through list alone" do
+    @taggable.skill_list = "ruby, rails, css"
+    @taggable.save
+    @taggable.reload
+    @taggable.should have(3).skills
+    @taggable.skill_list = "ruby, rails"
+    @taggable.save
+    @taggable.reload
+    @taggable.should have(2).skills
+  end
+  
+  it "should be able to find by tag" do
+    @taggable.skill_list = "ruby, rails, css"
+    @taggable.save
+    TaggableModel.find_tagged_with("ruby").first.should == @taggable
+  end
+  
+  it "should be able to find by tag with context" do
+    @taggable.skill_list = "ruby, rails, css"
+    @taggable.tag_list = "bob, charlie"
+    @taggable.save
+    TaggableModel.find_tagged_with("ruby").first.should == @taggable
+    TaggableModel.find_tagged_with("bob", :on => :skills).first.should_not == @taggable
+    TaggableModel.find_tagged_with("bob", :on => :tags).first.should == @taggable
+  end
+  
+  it "should not care about case" do
+    bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby")
+    frank = TaggableModel.create(:name => "Frank", :tag_list => "Ruby")
+    
+    Tag.find(:all).size.should == 1
+    TaggableModel.find_tagged_with("ruby").should == TaggableModel.find_tagged_with("Ruby")
+  end
+  
+  it "should be able to get tag counts on model as a whole" do
+    bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
+    frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
+    charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
+    TaggableModel.tag_counts.should_not be_empty
+    TaggableModel.skill_counts.should_not be_empty
+  end
+  
+  it "should be able to get tag counts on an association" do
+    bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
+    frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
+    charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
+    bob.tag_counts.first.count.should == 2
+    charlie.skill_counts.first.count.should == 1
+  end
+  
+  it "should be able to set a custom tag context list" do
+    bob = TaggableModel.create(:name => "Bob")
+    bob.set_tag_list_on(:rotors, "spinning, jumping")
+    bob.tag_list_on(:rotors).should == ["spinning","jumping"]
+    bob.save
+    bob.reload
+    bob.tags_on(:rotors).should_not be_empty
+  end
+  
+  it "should be able to find tagged on a custom tag context" do
+    bob = TaggableModel.create(:name => "Bob")
+    bob.set_tag_list_on(:rotors, "spinning, jumping")
+    bob.tag_list_on(:rotors).should == ["spinning","jumping"]
+    bob.save
+    TaggableModel.find_tagged_with("spinning", :on => :rotors).should_not be_empty
+  end
+  
+  describe "Single Table Inheritance" do
+    before do
+      [TaggableModel, Tag, Tagging, TaggableUser].each(&:delete_all)
+      @taggable = TaggableModel.new(:name => "taggable")
+      @inherited_same = InheritingTaggableModel.new(:name => "inherited same")
+      @inherited_different = AlteredInheritingTaggableModel.new(:name => "inherited different")
+    end
+    
+    it "should be able to save tags for inherited models" do
+      @inherited_same.tag_list = "bob, kelso"
+      @inherited_same.save
+      InheritingTaggableModel.find_tagged_with("bob").first.should == @inherited_same
+    end
+    
+    it "should find STI tagged models on the superclass" do
+      @inherited_same.tag_list = "bob, kelso"
+      @inherited_same.save
+      TaggableModel.find_tagged_with("bob").first.should == @inherited_same
+    end
+    
+    it "should be able to add on contexts only to some subclasses" do
+      @inherited_different.part_list = "fork, spoon"
+      @inherited_different.save
+      InheritingTaggableModel.find_tagged_with("fork", :on => :parts).should be_empty
+      AlteredInheritingTaggableModel.find_tagged_with("fork", :on => :parts).first.should == @inherited_different
+    end
+  end
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tagger_spec.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tagger_spec.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tagger_spec.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,23 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe "Tagger" do
+  before(:each) do
+    [TaggableModel, Tag, Tagging, TaggableUser].each(&:delete_all)
+    @user = TaggableUser.new
+    @taggable = TaggableModel.new(:name => "Bob Jones")
+  end
+  
+  it "should have taggings" do
+    @user.tag(@taggable, :with=>'ruby,scheme', :on=>:tags)
+    @user.owned_taggings.size == 2
+  end
+  
+  it "should have tags" do
+    @user.tag(@taggable, :with=>'ruby,scheme', :on=>:tags)
+    @user.owned_tags.size == 2
+  end
+  
+  it "is tagger" do
+    @user.is_tagger?.should(be_true)
+  end  
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tagging_spec.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tagging_spec.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tagging_spec.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,7 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe Tagging do
+  before(:each) do
+    @tagging = Tagging.new
+  end
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/schema.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/schema.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/schema.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,32 @@
+ActiveRecord::Schema.define :version => 0 do
+  create_table "taggings", :force => true do |t|
+    t.integer  "tag_id",        :limit => 11
+    t.integer  "taggable_id",   :limit => 11
+    t.string   "taggable_type"
+    t.string   "context"
+    t.datetime "created_at"
+    t.integer  "tagger_id",     :limit => 11
+    t.string   "tagger_type"
+  end
+
+  add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id"
+  add_index "taggings", ["taggable_id", "taggable_type", "context"], :name => "index_taggings_on_taggable_id_and_taggable_type_and_context"
+
+  create_table "tags", :force => true do |t|
+    t.string "name"
+  end
+  
+  create_table :taggable_models, :force => true do |t|
+    t.column :name, :string
+    t.column :type, :string
+    #t.column :cached_tag_list, :string
+  end
+  create_table :taggable_users, :force => true do |t|
+    t.column :name, :string
+  end
+  create_table :other_taggable_models, :force => true do |t|
+    t.column :name, :string
+    t.column :type, :string
+    #t.column :cached_tag_list, :string
+  end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/spec.opts
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/spec.opts	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/spec.opts	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,7 @@
+--colour
+--format
+specdoc
+--loadby
+mtime
+--reverse
+--backtrace
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/spec_helper.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/spec_helper.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/spec/spec_helper.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,33 @@
+require File.dirname(__FILE__) + '/../../../../spec/spec_helper'
+
+module Spec::Example::ExampleGroupMethods
+  alias :context :describe
+end
+
+plugin_spec_dir = File.dirname(__FILE__)
+ActiveRecord::Base.logger = Logger.new(plugin_spec_dir + "/debug.log")
+
+load(File.dirname(__FILE__) + '/schema.rb')
+
+class TaggableModel < ActiveRecord::Base
+  acts_as_taggable_on :tags, :languages
+  acts_as_taggable_on :skills
+end
+
+class OtherTaggableModel < ActiveRecord::Base
+  acts_as_taggable_on :tags, :languages
+end
+
+class InheritingTaggableModel < TaggableModel
+end
+
+class AlteredInheritingTaggableModel < TaggableModel
+  acts_as_taggable_on :parts
+end
+
+class TaggableUser < ActiveRecord::Base
+  acts_as_tagger
+end
+
+class UntaggableModel < ActiveRecord::Base
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/uninstall.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/uninstall.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/acts-as-taggable-on/uninstall.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1 @@
+# Uninstall hook code here

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/.gitignore
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/.gitignore	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/.gitignore	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,20 @@
+Icon?
+.DS_Store
+TAGS
+REVISION
+*.tmproj
+.settings
+.project
+.tasks-cache
+.svn
+/log/*.log
+/tmp/**/*
+/config/database.yml
+actionmailer_config_DONOTVERSION.rb
+*DONOTVERSION*
+/vendor/src/**/*
+/db/*.sqlite*
+/public/ac/*
+/coverage
+/doc/app
+/doc/plugins

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/CHANGELOG
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/CHANGELOG	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/CHANGELOG	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,68 @@
+h1. Internal Changes to code
+
+As always, this is just a copy-and-pasted version of the CHANGELOG file in the source code tree.
+
+h2. Changes for the May, 2008 version of restful-authentication
+
+h3. Changes to user model
+
+* recently_activated? belongs only if stateful
+* Gave migration a 40-char limit on remember_token & an index on users by login
+* **Much** stricter login and email validation
+* put length constraints in migration too
+* password in 6, 40
+* salt and remember_token now much less predictability
+
+h3. Changes to session_controller
+
+* use uniform logout function
+* use uniform remember_cookie functions
+* avoid calling logged_in? which will auto-log-you-in (safe in the face of
+  logout! call, but idiot-proof)
+* Moved reset_session into only the "now logged in" branch
+** wherever it goes, it has to be in front of the current_user= call
+** See more in README-Tradeoffs.txt
+* made a place to take action on failed login attempt
+* recycle login and remember_me setting on failed login
+* nil'ed out the password field in 'new' view
+
+h3. Changes to users_controller
+
+* use uniform logout function
+* use uniform remember_cookie functions
+* Moved reset_session into only the "now logged in" branch
+** wherever it goes, it has to be in front of the current_user= call
+** See more in README-Tradeoffs.txt
+* made the implicit login only happen for non-activationed sites
+* On a failed signup, kick you back to the signin screen (but strip out the password & confirmation)
+* more descriptive error messages in activate()
+
+h3. users_helper
+
+* link_to_user, link_to_current_user, link_to_signin_with_IP 
+* if_authorized(action, resource, &block) view function (with appropriate
+  warning)
+
+h3. authenticated_system
+
+* Made authorized? take optional arguments action=nil, resource=nil, *args
+  This makes its signature better match traditional approaches to access control
+  eg Reference Monitor in "Security Patterns":http://www.securitypatterns.org/patterns.html)
+* authorized? should be a helper too
+* added uniform logout! methods
+* format.any (as found in access_denied) doesn't work until
+  http://dev.rubyonrails.org/changeset/8987 lands.
+* cookies are now refreshed each time we cross the logged out/in barrier, as 
+  "best":http://palisade.plynt.com/issues/2004Jul/safe-auth-practices/
+  "practice":http://www.owasp.org/index.php/Session_Management#Regeneration_of_Session_Tokens
+
+h3. Other
+
+* Used escapes <%= %> in email templates (among other reasons, so courtenay's
+  "'dumbass' test":http://tinyurl.com/684g9t doesn't complain)
+* Added site key to generator, users.yml.
+* Made site key generation idempotent in the most crude and hackish way
+* 100% coverage apart from the stateful code. (needed some access_control
+  checks, and the http_auth stuff)
+* Stories!
+

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/README
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/README	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/README	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,176 @@
+h1. Restful Authentication Generator
+
+This widely-used plugin provides a foundation for securely managing user
+authentication:
+* Login / logout
+* Secure password handling
+* Account activation by validating email
+* Account approval / disabling by admin
+* Rudimentary hooks for authorization and access control.
+
+Several features were updated in May, 2008.  The newest version of this plugin
+may be found in
+  http://github.com/technoweenie/restful-authentication/tree/master
+While a "classic" (backward-compatible) version may be found in
+  http://github.com/technoweenie/restful-authentication/tree/classic
+
+  !! important: if you upgrade your site, existing user account !!
+  !! passwords will stop working unless you use --old-passwords !!
+
+This page has notes on
+* "Installation":#INSTALL
+* "Compatibility Warning":#COMPATIBILITY
+* "New Features":#AWESOME
+* "After installing":#POST-INSTALL
+
+See the "wiki":http://github.com/technoweenie/restful-authentication/wikis/home
+(or the notes/ directory) if you want to learn more about:
+
+* "Security Design Patterns":Security-Patterns with "snazzy diagram":http://github.com/technoweenie/restful-authentication/tree/master/notes/SecurityFramework.png
+* [[Authentication]] -- Lets a visitor identify herself (and lay  claim to her corresponding Roles and measure of Trust)
+* "Trust Metrics":Trustification -- Confidence we can rely on the outcomes of this visitor's actions.
+* [[Authorization]] and Policy -- Based on trust and identity, what actions may this visitor perform?
+* [[Access Control]] -- How the Authorization policy is actually enforced in your code (A: hopefully without turning it into  a spaghetti of if thens)
+* [[Rails Plugins]] for Authentication, Trust,  Authorization and Access Control
+* [[Tradeoffs]] -- for the paranoid or the curious, a rundown of tradeoffs made in the code
+* [[CHANGELOG]] -- Summary of changes to internals
+* [[TODO]] -- Ideas for how you can help
+
+These best version of the release notes are in the notes/ directory in the
+"source code":http://github.com/technoweenie/restful-authentication/tree/master
+-- look there for the latest version.  The wiki versions are taken (manually)
+from there.
+  
+***************************************************************************
+<a id="AWESOME"/> </a>
+h2. Exciting new features
+
+h3. Stories
+
+There are now RSpec stories that allow expressive, enjoyable tests for the
+authentication code. The flexible code for resource testing in stories was
+extended from "Ben Mabey's.":http://www.benmabey.com/2008/02/04/rspec-plain-text-stories-webrat-chunky-bacon/
+
+h3. Modularize to match security design patterns:
+
+* Authentication (currently: password, browser cookie token, HTTP basic)
+* Trust metric (email validation) 
+* Authorization (stateful roles)
+* Leave a flexible framework that will play nicely with other access control / policy definition / trust metric plugins
+
+h3. Other
+
+* Added a few helper methods for linking to user pages
+* Uniform handling of logout, remember_token
+* Stricter email, login field validation
+* Minor security fixes -- see CHANGELOG
+
+***************************************************************************
+<a id="COMPATIBILITY"/> </a>
+h2. Non-backwards compatible Changes
+
+Here are a few changes in the May 2008 release that increase "Defense in Depth"
+but may require changes to existing accounts
+
+* If you have an existing site, none of these changes are compelling enough to
+  warrant migrating your userbase.
+* If you are generating for a new site, all of these changes are low-impact.
+  You should apply them.
+
+h3. Passwords
+
+The new password encryption (using a site key salt and stretching) will break
+existing user accounts' passwords.  We recommend you use the --old-passwords
+option or write a migration tool and submit it as a patch.  See the
+[[Tradeoffs]] note for more information.
+
+h3. Validations
+
+By default, 
+
+***************************************************************************
+<a id="INSTALL"/> </a>
+h2. Installation
+
+This is a basic restful authentication generator for rails, taken from
+acts as authenticated.  Currently it requires Rails 1.2.6 or above.
+
+To use:
+
+  ./script/generate authenticated user sessions \
+    --include-activation \
+    --stateful \
+    --rspec \
+    --skip-migration \
+    --skip-routes \
+    --old-passwords
+
+* The first parameter specifies the model that gets created in signup (typically
+  a user or account model).  A model with migration is created, as well as a
+  basic controller with the create method. You probably want to say "User" here.
+
+* The second parameter specifies the session controller name.  This is the
+  controller that handles the actual login/logout function on the site.
+  (probably: "Session").
+
+* --include-activation: Generates the code for a ActionMailer and its respective
+  Activation Code through email.
+
+* --stateful: Builds in support for acts_as_state_machine and generates
+  activation code.  (@--stateful@ implies @--include-activation@). Based on the
+  idea at [[http://www.vaporbase.com/postings/stateful_authentication]]. Passing
+  @--skip-migration@ will skip the user migration, and @--skip-routes@ will skip
+  resource generation -- both useful if you've already run this generator.
+
+* --aasm: Works the same as stateful but uses the updated aasm gem
+
+* --rspec: Generate RSpec tests and Stories in place of standard rails tests.
+  This requires the
+    "RSpec and Rspec-on-rails plugins":http://rspec.info/
+  (make sure you "./script/generate rspec" after installing RSpec.)  The rspec
+  and story suite are much more thorough than the rails tests, and changes are
+  unlikely to be backported.
+  
+* --old-passwords: Use the older password scheme (see [[#COMPATIBILITY]], above)
+
+* --skip-migration: Don't generate a migration file for this model
+
+* --skip-routes: Don't generate a resource line in @config/routes.rb@
+
+
+***************************************************************************
+<a id="POST-INSTALL"/> </a>
+h2. After installing
+
+The below assumes a Model named 'User' and a Controller named 'Session'; please
+alter to suit. There are additional security minutae in @notes/README-Tradeoffs@
+-- only the paranoid or the curious need bother, though.
+
+* Add these familiar login URLs to your @config/routes.rb@ if you like:
+
+     map.signup  '/signup', :controller => 'users',   :action => 'new' @
+     map.login   '/login',  :controller => 'sessions', :action => 'new' @
+     map.logout  '/logout', :controller => 'sessions', :action => 'destroy' @
+    
+* With @--include-activation@, also add to your @config/routes.rb@:
+  
+    map.activate '/activate/:activation_code', :controller => 'users', :action => 'activate', :activation_code => nil) 
+    
+  and add an observer to @config/environment.rb@:
+  
+    config.active_record.observers = :users_observer
+
+* With @--stateful@, add an observer to config/environment.rb:
+  
+    config.active_record.observers = :user_observer
+  
+  and modify the users resource line to read
+  
+    map.resources :users, :member => { :suspend   => :put,
+                                       :unsuspend => :put,
+                                       :purge     => :delete } 
+
+* If you use a public repository for your code (such as github, rubyforge,
+  gitorious, etc.) make sure to NOT post your site_keys.rb (add a line like
+  '/config/initializers/site_keys.rb' to your .gitignore or do the svn ignore
+  dance), but make sure you DO keep it backed up somewhere safe.

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/Rakefile
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/Rakefile	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/Rakefile	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,22 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the restful_authentication plugin.'
+Rake::TestTask.new(:test) do |t|
+  t.libs << 'lib'
+  t.pattern = 'test/**/*_test.rb'
+  t.verbose = true
+end
+
+desc 'Generate documentation for the restful_authentication plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+  rdoc.rdoc_dir = 'rdoc'
+  rdoc.title    = 'RestfulAuthentication'
+  rdoc.options << '--line-numbers' << '--inline-source'
+  rdoc.rdoc_files.include('README')
+  rdoc.rdoc_files.include('lib/**/*.rb')
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/TODO
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/TODO	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/TODO	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,15 @@
+
+h3. Authentication security projects for a later date
+
+
+* Track 'failed logins this hour' and demand a captcha after say 5 failed logins
+  ("RECAPTCHA plugin.":http://agilewebdevelopment.com/plugins/recaptcha)
+  "De-proxy-ficate IP address": http://wiki.codemongers.com/NginxHttpRealIpModule
+
+* Make cookie spoofing a little harder: we set the user's cookie to
+  (remember_token), but store digest(remember_token, request_IP). A CSRF cookie
+  spoofer has to then at least also spoof the user's originating IP
+  (see "Secure Programs HOWTO":http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/web-authentication.html)
+
+* Log HTTP request on authentication / authorization failures
+  http://palisade.plynt.com/issues/2004Jul/safe-auth-practices  

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/USAGE
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/USAGE	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/USAGE	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1 @@
+./script/generate authenticated USERMODEL CONTROLLERNAME
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/authenticated_generator.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/authenticated_generator.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/authenticated_generator.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,478 @@
+require File.expand_path(File.dirname(__FILE__) + "/lib/insert_routes.rb")
+require 'digest/sha1'
+class AuthenticatedGenerator < Rails::Generator::NamedBase
+  default_options :skip_migration => false,
+                  :skip_routes    => false,
+                  :old_passwords  => false,
+                  :include_activation => false
+
+  attr_reader   :controller_name,
+                :controller_class_path,
+                :controller_file_path,
+                :controller_class_nesting,
+                :controller_class_nesting_depth,
+                :controller_class_name,
+                :controller_singular_name,
+                :controller_plural_name,
+                :controller_routing_name,                 # new_session_path
+                :controller_routing_path,                 # /session/new
+                :controller_controller_name,              # sessions
+                :controller_file_name
+  alias_method  :controller_table_name, :controller_plural_name
+  attr_reader   :model_controller_name,
+                :model_controller_class_path,
+                :model_controller_file_path,
+                :model_controller_class_nesting,
+                :model_controller_class_nesting_depth,
+                :model_controller_class_name,
+                :model_controller_singular_name,
+                :model_controller_plural_name,
+                :model_controller_routing_name,           # new_user_path
+                :model_controller_routing_path,           # /users/new
+                :model_controller_controller_name         # users
+  alias_method  :model_controller_file_name,  :model_controller_singular_name
+  alias_method  :model_controller_table_name, :model_controller_plural_name
+
+  def initialize(runtime_args, runtime_options = {})
+    super
+
+    @rspec = has_rspec?
+
+    @controller_name = (args.shift || 'sessions').pluralize
+    @model_controller_name = @name.pluralize
+
+    # sessions controller
+    base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name)
+    @controller_class_name_without_nesting, @controller_file_name, @controller_plural_name = inflect_names(base_name)
+    @controller_singular_name = @controller_file_name.singularize
+    if @controller_class_nesting.empty?
+      @controller_class_name = @controller_class_name_without_nesting
+    else
+      @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
+    end
+    @controller_routing_name  = @controller_singular_name
+    @controller_routing_path  = @controller_file_path.singularize
+    @controller_controller_name = @controller_plural_name
+
+    # model controller
+    base_name, @model_controller_class_path, @model_controller_file_path, @model_controller_class_nesting, @model_controller_class_nesting_depth = extract_modules(@model_controller_name)
+    @model_controller_class_name_without_nesting, @model_controller_singular_name, @model_controller_plural_name = inflect_names(base_name)
+
+    if @model_controller_class_nesting.empty?
+      @model_controller_class_name = @model_controller_class_name_without_nesting
+    else
+      @model_controller_class_name = "#{@model_controller_class_nesting}::#{@model_controller_class_name_without_nesting}"
+    end
+    @model_controller_routing_name    = @table_name
+    @model_controller_routing_path    = @model_controller_file_path
+    @model_controller_controller_name = @model_controller_plural_name
+
+    load_or_initialize_site_keys()
+    
+    if options[:dump_generator_attribute_names] 
+      dump_generator_attribute_names
+    end
+  end
+
+  def manifest
+    recorded_session = record do |m|
+      # Check for class naming collisions.
+      m.class_collisions controller_class_path,       "#{controller_class_name}Controller", # Sessions Controller
+                                                      "#{controller_class_name}Helper"
+      m.class_collisions model_controller_class_path, "#{model_controller_class_name}Controller", # Model Controller
+                                                      "#{model_controller_class_name}Helper"
+      m.class_collisions class_path,                  "#{class_name}", "#{class_name}Mailer", "#{class_name}MailerTest", "#{class_name}Observer"
+      m.class_collisions [], 'AuthenticatedSystem', 'AuthenticatedTestHelper'
+
+      # Controller, helper, views, and test directories.
+      m.directory File.join('app/models', class_path)
+      m.directory File.join('app/controllers', controller_class_path)
+      m.directory File.join('app/controllers', model_controller_class_path)
+      m.directory File.join('app/helpers', controller_class_path)
+      m.directory File.join('app/views', controller_class_path, controller_file_name)
+      m.directory File.join('app/views', class_path, "#{file_name}_mailer") if options[:include_activation]
+
+      m.directory File.join('app/controllers', model_controller_class_path)
+      m.directory File.join('app/helpers', model_controller_class_path)
+      m.directory File.join('app/views', model_controller_class_path, model_controller_file_name)
+      m.directory File.join('config/initializers')
+
+      if @rspec
+        m.directory File.join('spec/controllers', controller_class_path)
+        m.directory File.join('spec/controllers', model_controller_class_path)
+        m.directory File.join('spec/models', class_path)
+        m.directory File.join('spec/helpers', model_controller_class_path)
+        m.directory File.join('spec/fixtures', class_path)
+        m.directory File.join('stories', model_controller_file_path)
+        m.directory File.join('stories', 'steps')
+      else
+        m.directory File.join('test/functional', controller_class_path)
+        m.directory File.join('test/functional', model_controller_class_path)
+        m.directory File.join('test/unit', class_path)
+        m.directory File.join('test/fixtures', class_path)
+      end
+
+      m.template 'model.rb',
+                  File.join('app/models',
+                            class_path,
+                            "#{file_name}.rb")
+
+      if options[:include_activation]
+        %w( mailer observer ).each do |model_type|
+          m.template "#{model_type}.rb", File.join('app/models',
+                                               class_path,
+                                               "#{file_name}_#{model_type}.rb")
+        end
+      end
+
+      m.template 'controller.rb',
+                  File.join('app/controllers',
+                            controller_class_path,
+                            "#{controller_file_name}_controller.rb")
+
+      m.template 'model_controller.rb',
+                  File.join('app/controllers',
+                            model_controller_class_path,
+                            "#{model_controller_file_name}_controller.rb")
+
+      m.template 'authenticated_system.rb',
+                  File.join('lib', 'authenticated_system.rb')
+
+      m.template 'authenticated_test_helper.rb',
+                  File.join('lib', 'authenticated_test_helper.rb')
+
+      m.template 'site_keys.rb', site_keys_file
+
+      if @rspec
+        # RSpec Specs
+        m.template  'spec/controllers/users_controller_spec.rb',
+                    File.join('spec/controllers',
+                              model_controller_class_path,
+                              "#{model_controller_file_name}_controller_spec.rb")
+        m.template  'spec/controllers/sessions_controller_spec.rb',
+                    File.join('spec/controllers',
+                              controller_class_path,
+                              "#{controller_file_name}_controller_spec.rb")
+        m.template  'spec/controllers/access_control_spec.rb',
+                    File.join('spec/controllers',
+                              controller_class_path,
+                              "access_control_spec.rb")
+        m.template  'spec/controllers/authenticated_system_spec.rb',
+                    File.join('spec/controllers',
+                              controller_class_path,
+                              "authenticated_system_spec.rb")
+        m.template  'spec/helpers/users_helper_spec.rb',
+                    File.join('spec/helpers',
+                              model_controller_class_path,
+                              "#{table_name}_helper_spec.rb")
+        m.template  'spec/models/user_spec.rb',
+                    File.join('spec/models',
+                              class_path,
+                              "#{file_name}_spec.rb")
+        m.template 'spec/fixtures/users.yml',
+                    File.join('spec/fixtures',
+                               class_path,
+                              "#{table_name}.yml")
+
+        # RSpec Stories
+        m.template  'stories/steps/ra_navigation_steps.rb',
+         File.join('stories/steps/ra_navigation_steps.rb')
+        m.template  'stories/steps/ra_response_steps.rb',
+         File.join('stories/steps/ra_response_steps.rb')
+        m.template  'stories/steps/ra_resource_steps.rb',
+         File.join('stories/steps/ra_resource_steps.rb')
+        m.template  'stories/steps/user_steps.rb',
+         File.join('stories/steps/', "#{file_name}_steps.rb")
+        m.template  'stories/users/accounts.story',
+         File.join('stories', model_controller_file_path, 'accounts.story')
+        m.template  'stories/users/sessions.story',
+         File.join('stories', model_controller_file_path, 'sessions.story')
+        m.template  'stories/rest_auth_stories_helper.rb',
+         File.join('stories', 'rest_auth_stories_helper.rb')
+        m.template  'stories/rest_auth_stories.rb',
+         File.join('stories', 'rest_auth_stories.rb')
+
+      else
+        m.template 'test/functional_test.rb',
+                    File.join('test/functional',
+                              controller_class_path,
+                              "#{controller_file_name}_controller_test.rb")
+        m.template 'test/model_functional_test.rb',
+                    File.join('test/functional',
+                              model_controller_class_path,
+                              "#{model_controller_file_name}_controller_test.rb")
+        m.template 'test/unit_test.rb',
+                    File.join('test/unit',
+                              class_path,
+                              "#{file_name}_test.rb")
+        if options[:include_activation]
+          m.template 'test/mailer_test.rb', File.join('test/unit', class_path, "#{file_name}_mailer_test.rb")
+        end
+        m.template 'spec/fixtures/users.yml',
+                    File.join('test/fixtures',
+                              class_path,
+                              "#{table_name}.yml")
+      end
+
+      m.template 'helper.rb',
+                  File.join('app/helpers',
+                            controller_class_path,
+                            "#{controller_file_name}_helper.rb")
+
+      m.template 'model_helper.rb',
+                  File.join('app/helpers',
+                            model_controller_class_path,
+                            "#{model_controller_file_name}_helper.rb")
+
+
+      # Controller templates
+      m.template 'login.html.erb',  File.join('app/views', controller_class_path, controller_file_name, "new.html.erb")
+      m.template 'signup.html.erb', File.join('app/views', model_controller_class_path, model_controller_file_name, "new.html.erb")
+      m.template '_model_partial.html.erb', File.join('app/views', model_controller_class_path, model_controller_file_name, "_#{file_name}_bar.html.erb")
+
+      if options[:include_activation]
+        # Mailer templates
+        %w( activation signup_notification ).each do |action|
+          m.template "#{action}.html.erb",
+                     File.join('app/views', "#{file_name}_mailer", "#{action}.html.erb")
+        end
+      end
+
+      unless options[:skip_migration]
+        m.migration_template 'migration.rb', 'db/migrate', :assigns => {
+          :migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}"
+        }, :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}"
+      end
+      unless options[:skip_routes]
+        # Note that this fails for nested classes -- you're on your own with setting up the routes.
+        m.route_resource  controller_singular_name
+        m.route_resources model_controller_plural_name
+        m.route_name('signup',   '/signup',   {:controller => model_controller_plural_name, :action => 'new'})
+        m.route_name('register', '/register', {:controller => model_controller_plural_name, :action => 'create'})
+        m.route_name('login',    '/login',    {:controller => controller_controller_name, :action => 'new'})
+        m.route_name('logout',   '/logout',   {:controller => controller_controller_name, :action => 'destroy'})
+      end
+    end
+
+    #
+    # Post-install notes
+    #
+    action = File.basename($0) # grok the action from './script/generate' or whatever
+    case action
+    when "generate"
+      puts "Ready to generate."
+      puts ("-" * 70)
+      puts "Once finished, don't forget to:"
+      puts
+      if options[:include_activation]
+        puts "- Add an observer to config/environment.rb"
+        puts "    config.active_record.observers = :#{file_name}_observer"
+      end
+      if options[:aasm]
+        puts "- Install the acts_as_state_machine gem:"
+        puts "    sudo gem sources -a http://gems.github.com (If you haven't already)"        
+        puts "    sudo gem install rubyist-aasm"        
+      elsif options[:stateful]
+        puts "- Install the acts_as_state_machine plugin:"
+        puts "    svn export http://elitists.textdriven.com/svn/plugins/acts_as_state_machine/trunk vendor/plugins/acts_as_state_machine"
+      end
+      puts "- Add routes to these resources. In config/routes.rb, insert routes like:"
+      puts %(    map.signup '/signup', :controller => '#{model_controller_file_name}', :action => 'new')
+      puts %(    map.login  '/login',  :controller => '#{controller_file_name}', :action => 'new')
+      puts %(    map.logout '/logout', :controller => '#{controller_file_name}', :action => 'destroy')
+      if options[:include_activation]
+        puts %(    map.activate '/activate/:activation_code', :controller => '#{model_controller_file_name}', :action => 'activate', :activation_code => nil)
+      end
+      if options[:stateful]
+        puts  "  and modify the map.resources :#{model_controller_file_name} line to include these actions:"
+        puts  "    map.resources :#{model_controller_file_name}, :member => { :suspend => :put, :unsuspend => :put, :purge => :delete }"
+      end
+      puts
+      puts ("-" * 70)
+      puts
+      if $rest_auth_site_key_from_generator.blank?
+        puts "You've set a nil site key. This preserves existing users' passwords,"
+        puts "but allows dictionary attacks in the unlikely event your database is"
+        puts "compromised and your site code is not.  See the README for more."
+      elsif $rest_auth_keys_are_new
+        puts "We've create a new site key in #{site_keys_file}.  If you have existing"
+        puts "user accounts their passwords will no longer work (see README). As always,"
+        puts "keep this file safe but don't post it in public."
+      else
+        puts "We've reused the existing site key in #{site_keys_file}.  As always,"
+        puts "keep this file safe but don't post it in public."
+      end
+      puts
+      puts ("-" * 70)
+    when "destroy"
+      puts
+      puts ("-" * 70)
+      puts
+      puts "Thanks for using restful_authentication"
+      puts
+      puts "Don't forget to comment out the observer line in environment.rb"
+      puts "  (This was optional so it may not even be there)"
+      puts "  # config.active_record.observers = :#{file_name}_observer"
+      puts
+      puts ("-" * 70)
+      puts
+    else
+      puts "Didn't understand the action '#{action}' -- you might have missed the 'after running me' instructions."
+    end
+
+    #
+    # Do the thing
+    #
+    recorded_session
+  end
+
+  def has_rspec?
+    spec_dir = File.join(RAILS_ROOT, 'spec')
+    options[:rspec] ||= (File.exist?(spec_dir) && File.directory?(spec_dir)) unless (options[:rspec] == false)
+  end
+
+  #
+  # !! These must match the corresponding routines in by_password.rb !!
+  #
+  def secure_digest(*args)
+    Digest::SHA1.hexdigest(args.flatten.join('--'))
+  end
+  def make_token
+    secure_digest(Time.now, (1..10).map{ rand.to_s })
+  end
+  def password_digest(password, salt)
+    digest = $rest_auth_site_key_from_generator
+    $rest_auth_digest_stretches_from_generator.times do
+      digest = secure_digest(digest, salt, password, $rest_auth_site_key_from_generator)
+    end
+    digest
+  end
+
+  #
+  # Try to be idempotent:
+  # pull in the existing site key if any,
+  # seed it with reasonable defaults otherwise
+  #
+  def load_or_initialize_site_keys
+    case
+    when defined? REST_AUTH_SITE_KEY
+      if (options[:old_passwords]) && ((! REST_AUTH_SITE_KEY.blank?) || (REST_AUTH_DIGEST_STRETCHES != 1))
+        raise "You have a site key, but --old-passwords will overwrite it.  If this is really what you want, move the file #{site_keys_file} and re-run."
+      end
+      $rest_auth_site_key_from_generator         = REST_AUTH_SITE_KEY
+      $rest_auth_digest_stretches_from_generator = REST_AUTH_DIGEST_STRETCHES
+    when options[:old_passwords]
+      $rest_auth_site_key_from_generator         = nil
+      $rest_auth_digest_stretches_from_generator = 1
+      $rest_auth_keys_are_new                    = true
+    else
+      $rest_auth_site_key_from_generator         = make_token
+      $rest_auth_digest_stretches_from_generator = 10
+      $rest_auth_keys_are_new                    = true
+    end
+  end
+  def site_keys_file
+    File.join("config", "initializers", "site_keys.rb")
+  end
+
+protected
+  # Override with your own usage banner.
+  def banner
+    "Usage: #{$0} authenticated ModelName [ControllerName]"
+  end
+
+  def add_options!(opt)
+    opt.separator ''
+    opt.separator 'Options:'
+    opt.on("--skip-migration",
+      "Don't generate a migration file for this model")           { |v| options[:skip_migration] = v }
+    opt.on("--include-activation",
+      "Generate signup 'activation code' confirmation via email") { |v| options[:include_activation] = true }
+    opt.on("--stateful",
+      "Use acts_as_state_machine.  Assumes --include-activation") { |v| options[:include_activation] = options[:stateful] = true }
+    opt.on("--aasm",
+      "Use (gem) aasm.  Assumes --include-activation")            { |v| options[:include_activation] = options[:stateful] = options[:aasm] = true }      
+    opt.on("--rspec",
+      "Force rspec mode (checks for RAILS_ROOT/spec by default)") { |v| options[:rspec] = true }
+    opt.on("--no-rspec",
+      "Force test (not RSpec mode")                               { |v| options[:rspec] = false }
+    opt.on("--skip-routes",
+      "Don't generate a resource line in config/routes.rb")       { |v| options[:skip_routes] = v }
+    opt.on("--old-passwords",
+      "Use the older password encryption scheme (see README)")    { |v| options[:old_passwords] = v }
+    opt.on("--dump-generator-attrs",
+      "(generator debug helper)")                                 { |v| options[:dump_generator_attribute_names] = v }
+  end
+
+  def dump_generator_attribute_names
+    generator_attribute_names = [
+      :table_name,
+      :file_name,
+      :class_name,
+      :controller_name,
+      :controller_class_path,
+      :controller_file_path,
+      :controller_class_nesting,
+      :controller_class_nesting_depth,
+      :controller_class_name,
+      :controller_singular_name,
+      :controller_plural_name,
+      :controller_routing_name,                 # new_session_path
+      :controller_routing_path,                 # /session/new
+      :controller_controller_name,              # sessions
+      :controller_file_name,
+      :controller_table_name, :controller_plural_name,
+      :model_controller_name,
+      :model_controller_class_path,
+      :model_controller_file_path,
+      :model_controller_class_nesting,
+      :model_controller_class_nesting_depth,
+      :model_controller_class_name,
+      :model_controller_singular_name,
+      :model_controller_plural_name,
+      :model_controller_routing_name,           # new_user_path
+      :model_controller_routing_path,           # /users/new
+      :model_controller_controller_name,        # users
+      :model_controller_file_name,  :model_controller_singular_name,
+      :model_controller_table_name, :model_controller_plural_name,
+    ]
+    generator_attribute_names.each do |attr|
+      puts "%-40s %s" % ["#{attr}:", self.send(attr)]  # instance_variable_get("@#{attr.to_s}"
+    end
+
+  end
+end
+
+# ./script/generate authenticated FoonParent::Foon SporkParent::Spork -p --force --rspec --dump-generator-attrs
+# table_name:                              foon_parent_foons
+# file_name:                               foon
+# class_name:                              FoonParent::Foon
+# controller_name:                         SporkParent::Sporks
+# controller_class_path:                   spork_parent
+# controller_file_path:                    spork_parent/sporks
+# controller_class_nesting:                SporkParent
+# controller_class_nesting_depth:          1
+# controller_class_name:                   SporkParent::Sporks
+# controller_singular_name:                spork
+# controller_plural_name:                  sporks
+# controller_routing_name:                 spork
+# controller_routing_path:                 spork_parent/spork
+# controller_controller_name:              sporks
+# controller_file_name:                    sporks
+# controller_table_name:                   sporks
+# controller_plural_name:                  sporks
+# model_controller_name:                   FoonParent::Foons
+# model_controller_class_path:             foon_parent
+# model_controller_file_path:              foon_parent/foons
+# model_controller_class_nesting:          FoonParent
+# model_controller_class_nesting_depth:    1
+# model_controller_class_name:             FoonParent::Foons
+# model_controller_singular_name:          foons
+# model_controller_plural_name:            foons
+# model_controller_routing_name:           foon_parent_foons
+# model_controller_routing_path:           foon_parent/foons
+# model_controller_controller_name:        foons
+# model_controller_file_name:              foons
+# model_controller_singular_name:          foons
+# model_controller_table_name:             foons
+# model_controller_plural_name:            foons

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/lib/insert_routes.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/lib/insert_routes.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/lib/insert_routes.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,50 @@
+Rails::Generator::Commands::Create.class_eval do
+  def route_resource(*resources)
+    resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
+    sentinel = 'ActionController::Routing::Routes.draw do |map|'
+
+    logger.route "map.resource #{resource_list}"
+    unless options[:pretend]
+      gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
+        "#{match}\n  map.resource #{resource_list}\n"
+      end
+    end
+  end
+  
+  def route_name(name, path, options = {})
+    sentinel = 'ActionController::Routing::Routes.draw do |map|'
+    
+    logger.route "map.#{name} '#{path}', :controller => '#{options[:controller]}', :action => '#{options[:action]}'"
+    unless options[:pretend]
+      gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
+        "#{match}\n  map.#{name} '#{path}', :controller => '#{options[:controller]}', :action => '#{options[:action]}'"
+      end
+    end
+  end
+end
+
+Rails::Generator::Commands::Destroy.class_eval do
+  def route_resource(*resources)
+    resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
+    look_for = "\n  map.resource #{resource_list}\n"
+    logger.route "map.resource #{resource_list}"
+    gsub_file 'config/routes.rb', /(#{look_for})/mi, ''
+  end
+  
+  def route_name(name, path, options = {})
+    look_for =   "\n  map.#{name} '#{path}', :controller => '#{options[:controller]}', :action => '#{options[:action]}'"
+    logger.route "map.#{name} '#{path}',     :controller => '#{options[:controller]}', :action => '#{options[:action]}'"
+    gsub_file    'config/routes.rb', /(#{look_for})/mi, ''
+  end
+end
+
+Rails::Generator::Commands::List.class_eval do
+  def route_resource(*resources)
+    resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
+    logger.route "map.resource #{resource_list}"
+  end
+  
+  def route_name(name, path, options = {})
+    logger.route "map.#{name} '#{path}', :controller => '{options[:controller]}', :action => '#{options[:action]}'"
+  end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/_model_partial.html.erb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/_model_partial.html.erb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/_model_partial.html.erb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,8 @@
+<%% if logged_in? -%>
+  <div id="<%= file_name %>-bar-greeting">Logged in as <%%= link_to_current_<%= file_name %> :content_method => :login %></div>
+  <div id="<%= file_name %>-bar-action"  >(<%%= link_to "log out", logout_path, { :title => "Log out" }    %>)</div>
+<%% else -%>
+  <div id="<%= file_name %>-bar-greeting"><%%= abbr_tag_with_IP 'Not logged in', :style => 'border: none;' %></div>
+  <div id="<%= file_name %>-bar-action"  ><%%= link_to "Log in",  login_path,  { :title => "Log in" } %> /
+                               <%%= link_to "Sign up", signup_path, { :title => "Create an account" } %></div>
+<%% end -%>

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/activation.html.erb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/activation.html.erb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/activation.html.erb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,3 @@
+<%%=h @<%= file_name %>.login %>, your account has been activated.  Welcome aboard!
+
+  <%%=h @url %>

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/authenticated_system.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/authenticated_system.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/authenticated_system.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,187 @@
+module AuthenticatedSystem
+  protected
+    # Returns true or false if the <%= file_name %> is logged in.
+    # Preloads @current_<%= file_name %> with the <%= file_name %> model if they're logged in.
+    def logged_in?
+      !!current_<%= file_name %>
+    end
+
+    # Accesses the current <%= file_name %> from the session.
+    # Future calls avoid the database because nil is not equal to false.
+    def current_<%= file_name %>
+      @current_<%= file_name %> ||= (login_from_session || login_from_basic_auth || login_from_cookie) unless @current_<%= file_name %> == false
+    end
+
+    # Store the given <%= file_name %> id in the session.
+    def current_<%= file_name %>=(new_<%= file_name %>)
+      session[:<%= file_name %>_id] = new_<%= file_name %> ? new_<%= file_name %>.id : nil
+      @current_<%= file_name %> = new_<%= file_name %> || false
+    end
+
+    # Check if the <%= file_name %> 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 <%= file_name %>
+    # has the correct rights.
+    #
+    # Example:
+    #
+    #  # only allow nonbobs
+    #  def authorized?
+    #    current_<%= file_name %>.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 <%= file_name %> 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_<%= controller_routing_name %>_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_<%= file_name %> and #logged_in?
+    # available as ActionView helper methods.
+    def self.included(base)
+      base.send :helper_method, :current_<%= file_name %>, :logged_in?, :authorized? if base.respond_to? :helper_method
+    end
+
+    #
+    # Login
+    #
+
+    # Called from #current_<%= file_name %>.  First attempt to login by the <%= file_name %> id stored in the session.
+    def login_from_session
+      self.current_<%= file_name %> = <%= class_name %>.find_by_id(session[:<%= file_name %>_id]) if session[:<%= file_name %>_id]
+    end
+
+    # Called from #current_<%= file_name %>.  Now, attempt to login by basic authentication information.
+    def login_from_basic_auth
+      authenticate_with_http_basic do |login, password|
+        self.current_<%= file_name %> = <%= class_name %>.authenticate(login, password)
+      end
+    end
+    
+    #
+    # Logout
+    #
+
+    # Called from #current_<%= file_name %>.  Finaly, attempt to login by an expiring token in the cookie.
+    # for the paranoid: we _should_ be storing <%= file_name %>_token = hash(cookie_token, request IP)
+    def login_from_cookie
+      <%= file_name %> = cookies[:auth_token] && <%= class_name %>.find_by_remember_token(cookies[:auth_token])
+      if <%= file_name %> && <%= file_name %>.remember_token?
+        self.current_<%= file_name %> = <%= file_name %>
+        handle_remember_cookie! false # freshen cookie token (keeping date)
+        self.current_<%= file_name %>
+      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_<%= file_name %>.forget_me if @current_<%= file_name %>.is_a? <%= class_name %>
+      @current_<%= file_name %> = false     # not logged in, and don't do it for me
+      kill_remember_cookie!     # Kill client-side auth cookie
+      session[:<%= file_name %>_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_<%= file_name %>
+      (@current_<%= file_name %>.remember_token?) && 
+        (cookies[:auth_token] == @current_<%= file_name %>.remember_token)
+    end
+    
+    # Refresh the cookie auth token if it exists, create it otherwise
+    def handle_remember_cookie! new_cookie_flag
+      return unless @current_<%= file_name %>
+      case
+      when valid_remember_cookie? then @current_<%= file_name %>.refresh_token # keeping same expiry date
+      when new_cookie_flag        then @current_<%= file_name %>.remember_me 
+      else                             @current_<%= file_name %>.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_<%= file_name %>.remember_token,
+        :expires => @current_<%= file_name %>.remember_token_expires_at }
+    end
+
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/authenticated_test_helper.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/authenticated_test_helper.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/authenticated_test_helper.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,22 @@
+module AuthenticatedTestHelper
+  # Sets the current <%= file_name %> in the session from the <%= file_name %> fixtures.
+  def login_as(<%= file_name %>)
+    @request.session[:<%= file_name %>_id] = <%= file_name %> ? <%= table_name %>(<%= file_name %>).id : nil
+  end
+
+  def authorize_as(<%= file_name %>)
+    @request.env["HTTP_AUTHORIZATION"] = <%= file_name %> ? ActionController::HttpAuthentication::Basic.encode_credentials(<%= table_name %>(<%= file_name %>).login, 'monkey') : nil
+  end
+  
+<% if options[:rspec] -%>
+  # rspec
+  def mock_<%= file_name %>
+    <%= file_name %> = mock_model(<%= class_name %>, :id => 1,
+      :login  => 'user_name',
+      :name   => 'U. Surname',
+      :to_xml => "<%= class_name %>-in-XML", :to_json => "<%= class_name %>-in-JSON", 
+      :errors => [])
+    <%= file_name %>
+  end  
+<% end -%>
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/controller.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/controller.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/controller.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,43 @@
+# This controller handles the login/logout function of the site.  
+class <%= controller_class_name %>Controller < ApplicationController
+  # Be sure to include AuthenticationSystem in Application Controller instead
+  include AuthenticatedSystem
+
+  # render new.rhtml
+  def new
+  end
+
+  def create
+    logout_keeping_session!
+    <%= file_name %> = <%= class_name %>.authenticate(params[:login], params[:password])
+    if <%= file_name %>
+      # 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_<%= file_name %> = <%= file_name %>
+      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

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/helper.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/helper.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/helper.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,2 @@
+module <%= controller_class_name %>Helper
+end
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/login.html.erb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/login.html.erb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/login.html.erb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,16 @@
+<h1>Log In</h1>
+
+<%% form_tag <%= controller_routing_name %>_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 -%>

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/mailer.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/mailer.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/mailer.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,25 @@
+class <%= class_name %>Mailer < ActionMailer::Base
+  def signup_notification(<%= file_name %>)
+    setup_email(<%= file_name %>)
+    @subject    += 'Please activate your new account'
+  <% if options[:include_activation] %>
+    @body[:url]  = "http://YOURSITE/activate/#{<%= file_name %>.activation_code}"
+  <% else %>
+    @body[:url]  = "http://YOURSITE/login/" <% end %>
+  end
+  
+  def activation(<%= file_name %>)
+    setup_email(<%= file_name %>)
+    @subject    += 'Your account has been activated!'
+    @body[:url]  = "http://YOURSITE/"
+  end
+  
+  protected
+    def setup_email(<%= file_name %>)
+      @recipients  = "#{<%= file_name %>.email}"
+      @from        = "ADMINEMAIL"
+      @subject     = "[YOURSITE] "
+      @sent_on     = Time.now
+      @body[:<%= file_name %>] = <%= file_name %>
+    end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/migration.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/migration.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/migration.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,26 @@
+class <%= migration_name %> < ActiveRecord::Migration
+  def self.up
+    create_table "<%= table_name %>", :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
+<% if options[:include_activation] -%>
+      t.column :activation_code,           :string, :limit => 40
+      t.column :activated_at,              :datetime<% end %>
+<% if options[:stateful] -%>
+      t.column :state,                     :string, :null => :no, :default => 'passive'
+      t.column :deleted_at,                :datetime<% end %>
+    end
+    add_index :<%= table_name %>, :login, :unique => true
+  end
+
+  def self.down
+    drop_table "<%= table_name %>"
+  end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,69 @@
+require 'digest/sha1'
+
+class <%= class_name %> < ActiveRecord::Base
+  include Authentication
+  include Authentication::ByPassword
+  include Authentication::ByCookieToken
+<% if options[:aasm] -%>
+  include Authorization::AasmRoles
+<% elsif options[:stateful] -%>
+  include Authorization::StatefulRoles<% end %>
+  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 at a.wk
+  validates_uniqueness_of   :email,    :case_sensitive => false
+  validates_format_of       :email,    :with => RE_EMAIL_OK, :message => MSG_EMAIL_BAD
+
+  <% if options[:include_activation] && !options[:stateful] %>before_create :make_activation_code <% end %>
+
+  # 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
+
+<% if options[:include_activation] && !options[:stateful] %>
+  # Activates the user in the database.
+  def activate!
+    @activated = true
+    self.activated_at = Time.now.utc
+    self.activation_code = nil
+    save(false)
+  end
+
+  def active?
+    # the existence of an activation code means they have not activated yet
+    activation_code.nil?
+  end<% end %>
+
+  # 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 = <% if    options[:stateful]           %>find_in_state :first, :active, :conditions => {:login => login}<%
+           elsif options[:include_activation] %>find :first, :conditions => ['login = ? and activated_at IS NOT NULL', login]<%
+           else %>find_by_login(login)<% end %> # need to get the salt
+    u && u.authenticated?(password) ? u : nil
+  end
+
+  protected
+    
+<% if options[:include_activation] -%>
+    def make_activation_code
+  <% if options[:stateful] -%>
+      self.deleted_at = nil
+  <% end -%>
+      self.activation_code = self.class.make_token
+    end
+<% end %>
+
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model_controller.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model_controller.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model_controller.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,86 @@
+class <%= model_controller_class_name %>Controller < ApplicationController
+  # Be sure to include AuthenticationSystem in Application Controller instead
+  include AuthenticatedSystem
+  <% if options[:stateful] %>
+  # Protect these actions behind an admin login
+  # before_filter :admin_required, :only => [:suspend, :unsuspend, :destroy, :purge]
+  before_filter :find_<%= file_name %>, :only => [:suspend, :unsuspend, :destroy, :purge]
+  <% end %>
+
+  # render new.rhtml
+  def new
+    @<%= file_name %> = <%= class_name %>.new
+  end
+ 
+  def create
+    logout_keeping_session!
+    @<%= file_name %> = <%= class_name %>.new(params[:<%= file_name %>])
+<% if options[:stateful] -%>
+    @<%= file_name %>.register! if @<%= file_name %> && @<%= file_name %>.valid?
+    success = @<%= file_name %> && @<%= file_name %>.valid?
+<% else -%>
+    success = @<%= file_name %> && @<%= file_name %>.save
+<% end -%>
+    if success && @<%= file_name %>.errors.empty?
+      <% if !options[:include_activation] -%>
+      # Protects against session fixation attacks, causes request forgery
+      # protection if visitor resubmits an earlier form using back
+      # button. Uncomment if you understand the tradeoffs.
+      # reset session
+      self.current_<%= file_name %> = @<%= file_name %> # !! now logged in
+      <% end -%>
+      redirect_back_or_default('/')
+      flash[:notice] = "Thanks for signing up!  We're sending you an email with your activation code."
+    else
+      flash[:error]  = "We couldn't set up that account, sorry.  Please try again, or contact an admin (link is above)."
+      render :action => 'new'
+    end
+  end
+<% if options[:include_activation] %>
+  def activate
+    logout_keeping_session!
+    <%= file_name %> = <%= class_name %>.find_by_activation_code(params[:activation_code]) unless params[:activation_code].blank?
+    case
+    when (!params[:activation_code].blank?) && <%= file_name %> && !<%= file_name %>.active?
+      <%= file_name %>.activate!
+      flash[:notice] = "Signup complete! Please sign in to continue."
+      redirect_to '/login'
+    when params[:activation_code].blank?
+      flash[:error] = "The activation code was missing.  Please follow the URL from your email."
+      redirect_back_or_default('/')
+    else 
+      flash[:error]  = "We couldn't find a <%= file_name %> with that activation code -- check your email? Or maybe you've already activated -- try signing in."
+      redirect_back_or_default('/')
+    end
+  end
+<% end %><% if options[:stateful] %>
+  def suspend
+    @<%= file_name %>.suspend! 
+    redirect_to <%= model_controller_routing_name %>_path
+  end
+
+  def unsuspend
+    @<%= file_name %>.unsuspend! 
+    redirect_to <%= model_controller_routing_name %>_path
+  end
+
+  def destroy
+    @<%= file_name %>.delete!
+    redirect_to <%= model_controller_routing_name %>_path
+  end
+
+  def purge
+    @<%= file_name %>.destroy
+    redirect_to <%= model_controller_routing_name %>_path
+  end
+  
+  # There's no page here to update or destroy a <%= file_name %>.  If you add those, be
+  # smart -- make sure you check that the visitor is authorized to do so, that they
+  # supply their old password along with a new one to update it, etc.
+
+protected
+  def find_<%= file_name %>
+    @<%= file_name %> = <%= class_name %>.find(params[:id])
+  end
+<% end -%>
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model_helper.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model_helper.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model_helper.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,93 @@
+module <%= model_controller_class_name %>Helper
+  
+  #
+  # 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 ('<%= table_name %>/1')
+  #
+  # By default, their login is used as link text and link title (tooltip)
+  #
+  # Takes options
+  # * :content_text => 'Content text in place of <%= file_name %>.login', escaped with
+  #   the standard h() function.
+  # * :content_method => :<%= file_name %>_instance_method_to_call_for_content_text
+  # * :title_method => :<%= file_name %>_instance_method_to_call_for_title_attribute
+  # * as well as link_to()'s standard options
+  #
+  # Examples:
+  #   link_to_<%= file_name %> @<%= file_name %>
+  #   # => <a href="/<%= table_name %>/3" title="barmy">barmy</a>
+  #
+  #   # if you've added a .name attribute:
+  #  content_tag :span, :class => :vcard do
+  #    (link_to_<%= file_name %> <%= file_name %>, :class => 'fn n', :title_method => :login, :content_method => :name) +
+  #          ': ' + (content_tag :span, <%= file_name %>.email, :class => 'email')
+  #   end
+  #   # => <span class="vcard"><a href="/<%= table_name %>/3" title="barmy" class="fn n">Cyril Fotheringay-Phipps</a>: <span class="email">barmy at blandings.com</span></span>
+  #
+  #   link_to_<%= file_name %> @<%= file_name %>, :content_text => 'Your user page'
+  #   # => <a href="/<%= table_name %>/3" title="barmy" class="nickname">Your user page</a>
+  #
+  def link_to_<%= file_name %>(<%= file_name %>, options={})
+    raise "Invalid <%= file_name %>" unless <%= file_name %>
+    options.reverse_merge! :content_method => :login, :title_method => :login, :class => :nickname
+    content_text      = options.delete(:content_text)
+    content_text    ||= <%= file_name %>.send(options.delete(:content_method))
+    options[:title] ||= <%= file_name %>.send(options.delete(:title_method))
+    link_to h(content_text), <%= model_controller_routing_name.singularize %>_path(<%= file_name %>), 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_<%= file_name %>) or to the login page
+  # (using link_to_login_with_IP).
+  #
+  def link_to_current_<%= file_name %>(options={})
+    if current_<%= file_name %>
+      link_to_<%= file_name %> current_<%= file_name %>, options
+    else
+      content_text = options.delete(:content_text) || 'not signed in'
+      # kill ignored options from link_to_<%= file_name %>
+      [:content_method, :title_method].each{|opt| options.delete(opt)} 
+      link_to_login_with_IP content_text, options
+    end
+  end
+
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model_helper_spec.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model_helper_spec.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/model_helper_spec.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,158 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+include ApplicationHelper
+include <%= model_controller_class_name %>Helper
+
+describe "<%= model_controller_class_name %>Helper.link_to_<%= file_name %>" do
+  before do
+    @<%= file_name %> = <%= class_name %>.new({
+        :name  => '<%= class_name %> Name',
+        :login => '<%= file_name %>_name',
+      })
+    @<%= file_name %>.id = 1 # set non-attr_accessible specifically
+  end
+
+  it "should give an error on a nil <%= file_name %>" do
+    lambda { link_to_<%= file_name %>(nil) }.should raise_error('Invalid <%= file_name %>')
+  end
+
+  it "should link to the given <%= file_name %>" do
+    link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a[href='/<%= table_name %>/1']")
+  end
+
+  it "should use given link text if :content_text is specified" do
+    link_to_<%= file_name %>(@<%= file_name %>, :content_text => 'Hello there!').should have_tag("a", 'Hello there!')
+  end
+
+  it "should use the login as link text with no :content_method specified" do
+    link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a", '<%= file_name %>_name')
+  end
+
+  it "should use the name as link text with :content_method => :name" do
+    link_to_<%= file_name %>(@<%= file_name %>, :content_method => :name).should have_tag("a", '<%= class_name %> Name')
+  end
+
+  it "should use the login as title with no :title_method specified" do
+    link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a[title='<%= file_name %>_name']")
+  end
+
+  it "should use the name as link title with :content_method => :name" do
+    link_to_<%= file_name %>(@<%= file_name %>, :title_method => :name).should have_tag("a[title='<%= class_name %> Name']")
+  end
+
+  it "should have nickname as a class by default" do
+    link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a.nickname")
+  end
+
+  it "should take other classes and no longer have the nickname class" do
+    result = link_to_<%= file_name %>(@<%= file_name %>, :class => 'foo bar')
+    result.should have_tag("a.foo")
+    result.should have_tag("a.bar")
+  end
+end
+
+describe "<%= model_controller_class_name %>Helper.link_to_signin_with_IP" do
+  before do
+  end
+
+  it "should link to the signin_path" do
+    link_to_signin_with_IP().should have_tag("a[href='/signin']")
+  end
+
+  it "should use given link text if :content_text is specified" do
+    link_to_signin_with_IP(:content_text => 'Hello there!').should have_tag("a", 'Hello there!')
+  end
+
+  it "should use the login as link text with no :content_method specified" do
+    link_to_signin_with_IP().should have_tag("a", '0.0.0.0')
+  end
+
+  it "should use the ip address as title" do
+    link_to_signin_with_IP().should have_tag("a[title='0.0.0.0']")
+  end
+
+  it "should by default be like school in summer and have no class" do
+    link_to_signin_with_IP().should_not have_tag("a.nickname")
+  end
+  
+  it "should have some class if you tell it to" do
+    result = link_to_signin_with_IP(:class => 'foo bar')
+    result.should have_tag("a.foo")
+    result.should have_tag("a.bar")
+  end
+end
+
+describe "<%= model_controller_class_name %>Helper.link_to_current_<%= file_name %>, When logged in" do
+  fixtures :<%= table_name %>
+  include AuthenticatedTestHelper
+  before do
+    login_as(:quentin)
+  end
+
+  it "should link to the given <%= file_name %>" do
+    link_to_current_<%= file_name %>().should have_tag("a[href='/<%= table_name %>/1']")
+  end
+
+  it "should use given link text if :content_text is specified" do
+    link_to_current_user(:content_text => 'Hello there!').should have_tag("a", 'Hello there!')
+  end
+
+  it "should use the login as link text with no :content_method specified" do
+    link_to_current_user().should have_tag("a", 'quentin')
+  end
+
+  it "should use the name as link text with :content_method => :name" do
+    link_to_current_user(:content_method => :name).should have_tag("a", 'Quentin')
+  end
+
+  it "should use the login as title with no :title_method specified" do
+    link_to_current_user().should have_tag("a[title='quentin']")
+  end
+
+  it "should use the name as link title with :content_method => :name" do
+    link_to_current_user(:title_method => :name).should have_tag("a[title='Quentin']")
+  end
+
+  it "should have nickname as a class" do
+    link_to_current_user().should have_tag("a.nickname")
+  end
+
+  it "should take other classes and no longer have the nickname class" do
+    result = link_to_current_user(:class => 'foo bar')
+    result.should have_tag("a.foo")
+    result.should have_tag("a.bar")
+  end
+end
+
+
+
+describe "<%= model_controller_class_name %>Helper.link_to_current_user, When logged out" do
+  include AuthenticatedTestHelper
+  before do
+  end
+
+  it "should link to the signin_path" do
+    link_to_current_user().should have_tag("a[href='/signin']")
+  end
+
+  it "should use given link text if :content_text is specified" do
+    link_to_current_user(:content_text => 'Hello there!').should have_tag("a", 'Hello there!')
+  end
+
+  it "should use the IP address as link text with no :content_method specified" do
+    link_to_current_user().should have_tag("a", '0.0.0.0')
+  end
+
+  it "should use the ip address as title" do
+    link_to_current_user().should have_tag("a[title='0.0.0.0']")
+  end
+
+  it "should by default be like school in summer and have no class" do
+    link_to_current_user().should_not have_tag("a.nickname")
+  end
+
+  it "should have some class if you tell it to" do
+    result = link_to_current_user(:class => 'foo bar')
+    result.should have_tag("a.foo")
+    result.should have_tag("a.bar")
+  end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/observer.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/observer.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/observer.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,11 @@
+class <%= class_name %>Observer < ActiveRecord::Observer
+  def after_create(<%= file_name %>)
+    <%= class_name %>Mailer.deliver_signup_notification(<%= file_name %>)
+  end
+
+  def after_save(<%= file_name %>)
+  <% if options[:include_activation] %>
+    <%= class_name %>Mailer.deliver_activation(<%= file_name %>) if <%= file_name %>.recently_activated?
+  <% end %>
+  end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/signup.html.erb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/signup.html.erb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/signup.html.erb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,19 @@
+<h1>Sign up as a new user</h1>
+<%% @<%= file_name %>.password = @<%= file_name %>.password_confirmation = nil %>
+
+<%%= error_messages_for :<%= file_name %> %>
+<%% form_for :<%= file_name %>, :url => <%= model_controller_routing_name %>_path do |f| -%>
+<p><label for="login">Login</label><br/>
+<%%= f.text_field :login %></p>
+
+<p><label for="email">Email</label><br/>
+<%%= f.text_field :email %></p>
+
+<p><label for="password">Password</label><br/>
+<%%= f.password_field :password %></p>
+
+<p><label for="password_confirmation">Confirm Password</label><br/>
+<%%= f.password_field :password_confirmation %></p>
+
+<p><%%= submit_tag 'Sign up' %></p>
+<%% end -%>

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/signup_notification.html.erb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/signup_notification.html.erb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/signup_notification.html.erb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,8 @@
+Your account has been created.
+
+  Username: <%%=h @<%= file_name %>.login %>
+  Password: <%%=h @<%= file_name %>.password %>
+
+Visit this url to activate your account:
+
+  <%%=h @url %>

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/site_keys.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/site_keys.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/site_keys.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -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         = '<%= $rest_auth_site_key_from_generator %>'
+  
+# 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 = <%= $rest_auth_digest_stretches_from_generator %>

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/access_control_spec.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/access_control_spec.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/access_control_spec.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,90 @@
+require File.dirname(__FILE__) + '<%= ('/..'*controller_class_nesting_depth) + '/../spec_helper' %>'
+  # Be sure to include AuthenticatedTestHelper in spec/spec_helper.rb instead
+# Then, you can remove it from this and the units test.
+include AuthenticatedTestHelper
+
+#
+# A test controller with and without access controls
+#
+class AccessControlTestController < ApplicationController
+  before_filter :login_required, :only => :login_is_required
+  def login_is_required
+    respond_to do |format|
+      @foo = { 'success' => params[:format]||'no fmt given'}
+      format.html do render :text => "success"             end
+      format.xml  do render :xml  => @foo, :status => :ok  end
+      format.json do render :json => @foo, :status => :ok  end
+    end
+  end
+  def login_not_required
+    respond_to do |format|
+      @foo = { 'success' => params[:format]||'no fmt given'}
+      format.html do render :text => "success"             end
+      format.xml  do render :xml  => @foo, :status => :ok  end
+      format.json do render :json => @foo, :status => :ok  end
+    end
+  end
+end
+
+#
+# Access Control
+#
+
+ACCESS_CONTROL_FORMATS = [
+  ['',     "success"],
+  ['xml',  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash>\n  <success>xml</success>\n</hash>\n"],
+  ['json', "{\"success\": \"json\"}"],]
+ACCESS_CONTROL_AM_I_LOGGED_IN = [
+  [:i_am_logged_in,     :quentin],
+  [:i_am_not_logged_in, nil],]
+ACCESS_CONTROL_IS_LOGIN_REQD = [
+  :login_not_required,
+  :login_is_required,]
+
+describe AccessControlTestController do
+  fixtures        :<%= table_name %>
+  before do
+    # is there a better way to do this?
+    ActionController::Routing::Routes.add_route '/login_is_required',           :controller => 'access_control_test',   :action => 'login_is_required'
+    ActionController::Routing::Routes.add_route '/login_not_required',          :controller => 'access_control_test',   :action => 'login_not_required'
+  end
+
+  ACCESS_CONTROL_FORMATS.each do |format, success_text|
+    ACCESS_CONTROL_AM_I_LOGGED_IN.each do |logged_in_status, <%= file_name %>_login|
+      ACCESS_CONTROL_IS_LOGIN_REQD.each do |login_reqd_status|
+        describe "requesting #{format.blank? ? 'html' : format}; #{logged_in_status.to_s.humanize} and #{login_reqd_status.to_s.humanize}" do
+          before do
+            logout_keeping_session!
+            @<%= file_name %> = format.blank? ? login_as(<%= file_name %>_login) : authorize_as(<%= file_name %>_login)
+            get login_reqd_status.to_s, :format => format
+          end
+
+          if ((login_reqd_status == :login_not_required) ||
+              (login_reqd_status == :login_is_required && logged_in_status == :i_am_logged_in))
+            it "succeeds" do
+              response.should have_text(success_text)
+              response.code.to_s.should == '200'
+            end
+
+          elsif (login_reqd_status == :login_is_required && logged_in_status == :i_am_not_logged_in)
+            if ['html', ''].include? format
+              it "redirects me to the log in page" do
+                response.should redirect_to('/<%= controller_routing_path %>/new')
+              end
+            else
+              it "returns 'Access denied' and a 406 (Access Denied) status code" do
+                response.should have_text("HTTP Basic: Access denied.\n")
+                response.code.to_s.should == '401'
+              end
+            end
+
+          else
+            warn "Oops no case for #{format} and #{logged_in_status.to_s.humanize} and #{login_reqd_status.to_s.humanize}"
+          end
+        end # describe
+
+      end
+    end
+  end # cases
+
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/authenticated_system_spec.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/authenticated_system_spec.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/authenticated_system_spec.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,101 @@
+require File.dirname(__FILE__) + '<%= ('/..'*controller_class_nesting_depth) + '/../spec_helper' %>'
+
+# Be sure to include AuthenticatedTestHelper in spec/spec_helper.rb instead
+# Then, you can remove it from this and the units test.
+include AuthenticatedTestHelper
+include AuthenticatedSystem
+
+describe <%= controller_class_name %>Controller do
+  fixtures :<%= table_name %>
+  
+  before do
+    # FIXME -- <%= controller_file_name %> controller not testing xml logins 
+    stub!(:authenticate_with_http_basic).and_return nil
+  end    
+  describe "logout_killing_session!" do
+    before do
+      login_as :quentin
+      stub!(:reset_session)
+    end
+    it 'resets the session'         do should_receive(:reset_session);         logout_killing_session! end
+    it 'kills my auth_token cookie' do should_receive(:kill_remember_cookie!); logout_killing_session! end
+    it 'nils the current <%= file_name %>'      do logout_killing_session!; current_<%= file_name %>.should be_nil end
+    it 'kills :<%= file_name %>_id session' do
+      session.stub!(:[]=)
+      session.should_receive(:[]=).with(:<%= file_name %>_id, nil).at_least(:once)
+      logout_killing_session!
+    end
+    it 'forgets me' do    
+      current_<%= file_name %>.remember_me
+      current_<%= file_name %>.remember_token.should_not be_nil; current_<%= file_name %>.remember_token_expires_at.should_not be_nil
+      <%= class_name %>.find(1).remember_token.should_not be_nil; <%= class_name %>.find(1).remember_token_expires_at.should_not be_nil
+      logout_killing_session!
+      <%= class_name %>.find(1).remember_token.should     be_nil; <%= class_name %>.find(1).remember_token_expires_at.should     be_nil
+    end
+  end
+
+  describe "logout_keeping_session!" do
+    before do
+      login_as :quentin
+      stub!(:reset_session)
+    end
+    it 'does not reset the session' do should_not_receive(:reset_session);   logout_keeping_session! end
+    it 'kills my auth_token cookie' do should_receive(:kill_remember_cookie!); logout_keeping_session! end
+    it 'nils the current <%= file_name %>'      do logout_keeping_session!; current_<%= file_name %>.should be_nil end
+    it 'kills :<%= file_name %>_id session' do
+      session.stub!(:[]=)
+      session.should_receive(:[]=).with(:<%= file_name %>_id, nil).at_least(:once)
+      logout_keeping_session!
+    end
+    it 'forgets me' do    
+      current_<%= file_name %>.remember_me
+      current_<%= file_name %>.remember_token.should_not be_nil; current_<%= file_name %>.remember_token_expires_at.should_not be_nil
+      <%= class_name %>.find(1).remember_token.should_not be_nil; <%= class_name %>.find(1).remember_token_expires_at.should_not be_nil
+      logout_keeping_session!
+      <%= class_name %>.find(1).remember_token.should     be_nil; <%= class_name %>.find(1).remember_token_expires_at.should     be_nil
+    end
+  end
+  
+  describe 'When logged out' do 
+    it "should not be authorized?" do
+      authorized?().should be_false
+    end    
+  end
+
+  #
+  # Cookie Login
+  #
+  describe "Logging in by cookie" do
+    def set_remember_token token, time
+      @<%= file_name %>[:remember_token]            = token; 
+      @<%= file_name %>[:remember_token_expires_at] = time
+      @<%= file_name %>.save!
+    end    
+    before do 
+      @<%= file_name %> = <%= class_name %>.find(:first); 
+      set_remember_token 'hello!', 5.minutes.from_now
+    end    
+    it 'logs in with cookie' do
+      stub!(:cookies).and_return({ :auth_token => 'hello!' })
+      logged_in?.should be_true
+    end
+    
+    it 'fails cookie login with bad cookie' do
+      should_receive(:cookies).at_least(:once).and_return({ :auth_token => 'i_haxxor_joo' })
+      logged_in?.should_not be_true
+    end
+    
+    it 'fails cookie login with no cookie' do
+      set_remember_token nil, nil
+      should_receive(:cookies).at_least(:once).and_return({ })
+      logged_in?.should_not be_true
+    end
+    
+    it 'fails expired cookie login' do
+      set_remember_token 'hello!', 5.minutes.ago
+      stub!(:cookies).and_return({ :auth_token => 'hello!' })
+      logged_in?.should_not be_true
+    end
+  end
+  
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/sessions_controller_spec.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/sessions_controller_spec.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/sessions_controller_spec.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,139 @@
+require File.dirname(__FILE__) + '<%= ('/..'*controller_class_nesting_depth) + '/../spec_helper' %>'
+
+# Be sure to include AuthenticatedTestHelper in spec/spec_helper.rb instead
+# Then, you can remove it from this and the units test.
+include AuthenticatedTestHelper
+
+describe <%= controller_class_name %>Controller do
+  fixtures        :<%= table_name %>
+  before do 
+    @<%= file_name %>  = mock_<%= file_name %>
+    @login_params = { :login => 'quentin', :password => 'test' }
+    <%= class_name %>.stub!(:authenticate).with(@login_params[:login], @login_params[:password]).and_return(@<%= file_name %>)
+  end
+  def do_create
+    post :create, @login_params
+  end
+  describe "on successful login," do
+    [ [:nil,       nil,            nil],
+      [:expired,   'valid_token',  15.minutes.ago],
+      [:different, 'i_haxxor_joo', 15.minutes.from_now], 
+      [:valid,     'valid_token',  15.minutes.from_now]
+        ].each do |has_request_token, token_value, token_expiry|
+      [ true, false ].each do |want_remember_me|
+        describe "my request cookie token is #{has_request_token.to_s}," do
+          describe "and ask #{want_remember_me ? 'to' : 'not to'} be remembered" do 
+            before do
+              @ccookies = mock('cookies')
+              controller.stub!(:cookies).and_return(@ccookies)
+              @ccookies.stub!(:[]).with(:auth_token).and_return(token_value)
+              @ccookies.stub!(:delete).with(:auth_token)
+              @ccookies.stub!(:[]=)
+              @<%= file_name %>.stub!(:remember_me) 
+              @<%= file_name %>.stub!(:refresh_token) 
+              @<%= file_name %>.stub!(:forget_me)
+              @<%= file_name %>.stub!(:remember_token).and_return(token_value) 
+              @<%= file_name %>.stub!(:remember_token_expires_at).and_return(token_expiry)
+              @<%= file_name %>.stub!(:remember_token?).and_return(has_request_token == :valid)
+              if want_remember_me
+                @login_params[:remember_me] = '1'
+              else 
+                @login_params[:remember_me] = '0'
+              end
+            end
+            it "kills existing login"        do controller.should_receive(:logout_keeping_session!); do_create; end    
+            it "authorizes me"               do do_create; controller.authorized?().should be_true;   end    
+            it "logs me in"                  do do_create; controller.logged_in?().should  be_true  end    
+            it "greets me nicely"            do do_create; response.flash[:notice].should =~ /success/i   end
+            it "sets/resets/expires cookie"  do controller.should_receive(:handle_remember_cookie!).with(want_remember_me); do_create end
+            it "sends a cookie"              do controller.should_receive(:send_remember_cookie!);  do_create end
+            it 'redirects to the home page'  do do_create; response.should redirect_to('/')   end
+            it "does not reset my session"   do controller.should_not_receive(:reset_session).and_return nil; do_create end # change if you uncomment the reset_session path
+            if (has_request_token == :valid)
+              it 'does not make new token'   do @<%= file_name %>.should_not_receive(:remember_me);   do_create end
+              it 'does refresh token'        do @<%= file_name %>.should_receive(:refresh_token);     do_create end 
+              it "sets an auth cookie"       do do_create;  end
+            else
+              if want_remember_me
+                it 'makes a new token'       do @<%= file_name %>.should_receive(:remember_me);       do_create end 
+                it "does not refresh token"  do @<%= file_name %>.should_not_receive(:refresh_token); do_create end
+                it "sets an auth cookie"       do do_create;  end
+              else 
+                it 'does not make new token' do @<%= file_name %>.should_not_receive(:remember_me);   do_create end
+                it 'does not refresh token'  do @<%= file_name %>.should_not_receive(:refresh_token); do_create end 
+                it 'kills user token'        do @<%= file_name %>.should_receive(:forget_me);         do_create end 
+              end
+            end
+          end # inner describe
+        end
+      end
+    end
+  end
+  
+  describe "on failed login" do
+    before do
+      <%= class_name %>.should_receive(:authenticate).with(anything(), anything()).and_return(nil)
+      login_as :quentin
+    end
+    it 'logs out keeping session'   do controller.should_receive(:logout_keeping_session!); do_create end
+    it 'flashes an error'           do do_create; flash[:error].should =~ /Couldn't log you in as 'quentin'/ end
+    it 'renders the log in page'    do do_create; response.should render_template('new')  end
+    it "doesn't log me in"          do do_create; controller.logged_in?().should == false end
+    it "doesn't send password back" do 
+      @login_params[:password] = 'FROBNOZZ'
+      do_create
+      response.should_not have_text(/FROBNOZZ/i)
+    end
+  end
+
+  describe "on signout" do
+    def do_destroy
+      get :destroy
+    end
+    before do 
+      login_as :quentin
+    end
+    it 'logs me out'                   do controller.should_receive(:logout_killing_session!); do_destroy end
+    it 'redirects me to the home page' do do_destroy; response.should be_redirect     end
+  end
+  
+end
+
+describe <%= controller_class_name %>Controller do
+  describe "route generation" do
+    it "should route the new <%= controller_controller_name %> action correctly" do
+      route_for(:controller => '<%= controller_controller_name %>', :action => 'new').should == "/login"
+    end
+    it "should route the create <%= controller_controller_name %> correctly" do
+      route_for(:controller => '<%= controller_controller_name %>', :action => 'create').should == "/<%= controller_routing_path %>"
+    end
+    it "should route the destroy <%= controller_controller_name %> action correctly" do
+      route_for(:controller => '<%= controller_controller_name %>', :action => 'destroy').should == "/logout"
+    end
+  end
+  
+  describe "route recognition" do
+    it "should generate params from GET /login correctly" do
+      params_from(:get, '/login').should == {:controller => '<%= controller_controller_name %>', :action => 'new'}
+    end
+    it "should generate params from POST /<%= controller_routing_path %> correctly" do
+      params_from(:post, '/<%= controller_routing_path %>').should == {:controller => '<%= controller_controller_name %>', :action => 'create'}
+    end
+    it "should generate params from DELETE /<%= controller_routing_path %> correctly" do
+      params_from(:delete, '/logout').should == {:controller => '<%= controller_controller_name %>', :action => 'destroy'}
+    end
+  end
+  
+  describe "named routing" do
+    before(:each) do
+      get :new
+    end
+    it "should route <%= controller_routing_name %>_path() correctly" do
+      <%= controller_routing_name %>_path().should == "/<%= controller_routing_path %>"
+    end
+    it "should route new_<%= controller_routing_name %>_path() correctly" do
+      new_<%= controller_routing_name %>_path().should == "/<%= controller_routing_path %>/new"
+    end
+  end
+  
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/users_controller_spec.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/users_controller_spec.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/controllers/users_controller_spec.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,198 @@
+require File.dirname(__FILE__) + '<%= ('/..'*model_controller_class_nesting_depth) + '/../spec_helper' %>'
+  
+# Be sure to include AuthenticatedTestHelper in spec/spec_helper.rb instead
+# Then, you can remove it from this and the units test.
+include AuthenticatedTestHelper
+
+describe <%= model_controller_class_name %>Controller do
+  fixtures :<%= table_name %>
+
+  it 'allows signup' do
+    lambda do
+      create_<%= file_name %>
+      response.should be_redirect
+    end.should change(<%= class_name %>, :count).by(1)
+  end
+
+  <% if options[:stateful] %>
+  it 'signs up user in pending state' do
+    create_<%= file_name %>
+    assigns(:<%= file_name %>).reload
+    assigns(:<%= file_name %>).should be_pending
+  end<% end %>
+
+<% if options[:include_activation] -%>
+  it 'signs up user with activation code' do
+    create_<%= file_name %>
+    assigns(:<%= file_name %>).reload
+    assigns(:<%= file_name %>).activation_code.should_not be_nil
+  end<% end -%>
+
+  it 'requires login on signup' do
+    lambda do
+      create_<%= file_name %>(:login => nil)
+      assigns[:<%= file_name %>].errors.on(:login).should_not be_nil
+      response.should be_success
+    end.should_not change(<%= class_name %>, :count)
+  end
+  
+  it 'requires password on signup' do
+    lambda do
+      create_<%= file_name %>(:password => nil)
+      assigns[:<%= file_name %>].errors.on(:password).should_not be_nil
+      response.should be_success
+    end.should_not change(<%= class_name %>, :count)
+  end
+  
+  it 'requires password confirmation on signup' do
+    lambda do
+      create_<%= file_name %>(:password_confirmation => nil)
+      assigns[:<%= file_name %>].errors.on(:password_confirmation).should_not be_nil
+      response.should be_success
+    end.should_not change(<%= class_name %>, :count)
+  end
+
+  it 'requires email on signup' do
+    lambda do
+      create_<%= file_name %>(:email => nil)
+      assigns[:<%= file_name %>].errors.on(:email).should_not be_nil
+      response.should be_success
+    end.should_not change(<%= class_name %>, :count)
+  end
+  
+  <% if options[:include_activation] %>
+  it 'activates user' do
+    <%= class_name %>.authenticate('aaron', 'monkey').should be_nil
+    get :activate, :activation_code => <%= table_name %>(:aaron).activation_code
+    response.should redirect_to('/login')
+    flash[:notice].should_not be_nil
+    flash[:error ].should     be_nil
+    <%= class_name %>.authenticate('aaron', 'monkey').should == <%= table_name %>(:aaron)
+  end
+  
+  it 'does not activate user without key' do
+    get :activate
+    flash[:notice].should     be_nil
+    flash[:error ].should_not be_nil
+  end
+  
+  it 'does not activate user with blank key' do
+    get :activate, :activation_code => ''
+    flash[:notice].should     be_nil
+    flash[:error ].should_not be_nil
+  end
+  
+  it 'does not activate user with bogus key' do
+    get :activate, :activation_code => 'i_haxxor_joo'
+    flash[:notice].should     be_nil
+    flash[:error ].should_not be_nil
+  end<% end %>
+  
+  def create_<%= file_name %>(options = {})
+    post :create, :<%= file_name %> => { :login => 'quire', :email => 'quire at example.com',
+      :password => 'quire69', :password_confirmation => 'quire69' }.merge(options)
+  end
+end
+
+describe <%= model_controller_class_name %>Controller do
+  describe "route generation" do
+    it "should route <%= model_controller_controller_name %>'s 'index' action correctly" do
+      route_for(:controller => '<%= model_controller_controller_name %>', :action => 'index').should == "/<%= model_controller_routing_path %>"
+    end
+    
+    it "should route <%= model_controller_controller_name %>'s 'new' action correctly" do
+      route_for(:controller => '<%= model_controller_controller_name %>', :action => 'new').should == "/signup"
+    end
+    
+    it "should route {:controller => '<%= model_controller_controller_name %>', :action => 'create'} correctly" do
+      route_for(:controller => '<%= model_controller_controller_name %>', :action => 'create').should == "/register"
+    end
+    
+    it "should route <%= model_controller_controller_name %>'s 'show' action correctly" do
+      route_for(:controller => '<%= model_controller_controller_name %>', :action => 'show', :id => '1').should == "/<%= model_controller_routing_path %>/1"
+    end
+    
+    it "should route <%= model_controller_controller_name %>'s 'edit' action correctly" do
+      route_for(:controller => '<%= model_controller_controller_name %>', :action => 'edit', :id => '1').should == "/<%= model_controller_routing_path %>/1/edit"
+    end
+    
+    it "should route <%= model_controller_controller_name %>'s 'update' action correctly" do
+      route_for(:controller => '<%= model_controller_controller_name %>', :action => 'update', :id => '1').should == "/<%= model_controller_routing_path %>/1"
+    end
+    
+    it "should route <%= model_controller_controller_name %>'s 'destroy' action correctly" do
+      route_for(:controller => '<%= model_controller_controller_name %>', :action => 'destroy', :id => '1').should == "/<%= model_controller_routing_path %>/1"
+    end
+  end
+  
+  describe "route recognition" do
+    it "should generate params for <%= model_controller_controller_name %>'s index action from GET /<%= model_controller_routing_path %>" do
+      params_from(:get, '/<%= model_controller_routing_path %>').should == {:controller => '<%= model_controller_controller_name %>', :action => 'index'}
+      params_from(:get, '/<%= model_controller_routing_path %>.xml').should == {:controller => '<%= model_controller_controller_name %>', :action => 'index', :format => 'xml'}
+      params_from(:get, '/<%= model_controller_routing_path %>.json').should == {:controller => '<%= model_controller_controller_name %>', :action => 'index', :format => 'json'}
+    end
+    
+    it "should generate params for <%= model_controller_controller_name %>'s new action from GET /<%= model_controller_routing_path %>" do
+      params_from(:get, '/<%= model_controller_routing_path %>/new').should == {:controller => '<%= model_controller_controller_name %>', :action => 'new'}
+      params_from(:get, '/<%= model_controller_routing_path %>/new.xml').should == {:controller => '<%= model_controller_controller_name %>', :action => 'new', :format => 'xml'}
+      params_from(:get, '/<%= model_controller_routing_path %>/new.json').should == {:controller => '<%= model_controller_controller_name %>', :action => 'new', :format => 'json'}
+    end
+    
+    it "should generate params for <%= model_controller_controller_name %>'s create action from POST /<%= model_controller_routing_path %>" do
+      params_from(:post, '/<%= model_controller_routing_path %>').should == {:controller => '<%= model_controller_controller_name %>', :action => 'create'}
+      params_from(:post, '/<%= model_controller_routing_path %>.xml').should == {:controller => '<%= model_controller_controller_name %>', :action => 'create', :format => 'xml'}
+      params_from(:post, '/<%= model_controller_routing_path %>.json').should == {:controller => '<%= model_controller_controller_name %>', :action => 'create', :format => 'json'}
+    end
+    
+    it "should generate params for <%= model_controller_controller_name %>'s show action from GET /<%= model_controller_routing_path %>/1" do
+      params_from(:get , '/<%= model_controller_routing_path %>/1').should == {:controller => '<%= model_controller_controller_name %>', :action => 'show', :id => '1'}
+      params_from(:get , '/<%= model_controller_routing_path %>/1.xml').should == {:controller => '<%= model_controller_controller_name %>', :action => 'show', :id => '1', :format => 'xml'}
+      params_from(:get , '/<%= model_controller_routing_path %>/1.json').should == {:controller => '<%= model_controller_controller_name %>', :action => 'show', :id => '1', :format => 'json'}
+    end
+    
+    it "should generate params for <%= model_controller_controller_name %>'s edit action from GET /<%= model_controller_routing_path %>/1/edit" do
+      params_from(:get , '/<%= model_controller_routing_path %>/1/edit').should == {:controller => '<%= model_controller_controller_name %>', :action => 'edit', :id => '1'}
+    end
+    
+    it "should generate params {:controller => '<%= model_controller_controller_name %>', :action => update', :id => '1'} from PUT /<%= model_controller_routing_path %>/1" do
+      params_from(:put , '/<%= model_controller_routing_path %>/1').should == {:controller => '<%= model_controller_controller_name %>', :action => 'update', :id => '1'}
+      params_from(:put , '/<%= model_controller_routing_path %>/1.xml').should == {:controller => '<%= model_controller_controller_name %>', :action => 'update', :id => '1', :format => 'xml'}
+      params_from(:put , '/<%= model_controller_routing_path %>/1.json').should == {:controller => '<%= model_controller_controller_name %>', :action => 'update', :id => '1', :format => 'json'}
+    end
+    
+    it "should generate params for <%= model_controller_controller_name %>'s destroy action from DELETE /<%= model_controller_routing_path %>/1" do
+      params_from(:delete, '/<%= model_controller_routing_path %>/1').should == {:controller => '<%= model_controller_controller_name %>', :action => 'destroy', :id => '1'}
+      params_from(:delete, '/<%= model_controller_routing_path %>/1.xml').should == {:controller => '<%= model_controller_controller_name %>', :action => 'destroy', :id => '1', :format => 'xml'}
+      params_from(:delete, '/<%= model_controller_routing_path %>/1.json').should == {:controller => '<%= model_controller_controller_name %>', :action => 'destroy', :id => '1', :format => 'json'}
+    end
+  end
+  
+  describe "named routing" do
+    before(:each) do
+      get :new
+    end
+    
+    it "should route <%= model_controller_routing_name %>_path() to /<%= model_controller_routing_path %>" do
+      <%= model_controller_routing_name %>_path().should == "/<%= model_controller_routing_path %>"
+      formatted_<%= model_controller_routing_name %>_path(:format => 'xml').should == "/<%= model_controller_routing_path %>.xml"
+      formatted_<%= model_controller_routing_name %>_path(:format => 'json').should == "/<%= model_controller_routing_path %>.json"
+    end
+    
+    it "should route new_<%= model_controller_routing_name.singularize %>_path() to /<%= model_controller_routing_path %>/new" do
+      new_<%= model_controller_routing_name.singularize %>_path().should == "/<%= model_controller_routing_path %>/new"
+      formatted_new_<%= model_controller_routing_name.singularize %>_path(:format => 'xml').should == "/<%= model_controller_routing_path %>/new.xml"
+      formatted_new_<%= model_controller_routing_name.singularize %>_path(:format => 'json').should == "/<%= model_controller_routing_path %>/new.json"
+    end
+    
+    it "should route <%= model_controller_routing_name.singularize %>_(:id => '1') to /<%= model_controller_routing_path %>/1" do
+      <%= model_controller_routing_name.singularize %>_path(:id => '1').should == "/<%= model_controller_routing_path %>/1"
+      formatted_<%= model_controller_routing_name.singularize %>_path(:id => '1', :format => 'xml').should == "/<%= model_controller_routing_path %>/1.xml"
+      formatted_<%= model_controller_routing_name.singularize %>_path(:id => '1', :format => 'json').should == "/<%= model_controller_routing_path %>/1.json"
+    end
+    
+    it "should route edit_<%= model_controller_routing_name.singularize %>_path(:id => '1') to /<%= model_controller_routing_path %>/1/edit" do
+      edit_<%= model_controller_routing_name.singularize %>_path(:id => '1').should == "/<%= model_controller_routing_path %>/1/edit"
+    end
+  end
+  
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/fixtures/users.yml
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/fixtures/users.yml	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/fixtures/users.yml	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,60 @@
+<%
+  ## this code must match that in templates/model.rb
+  require 'digest/sha1'
+  def make_fake_token
+    @fake_token_counter ||= 0
+    @fake_token_counter +=  1
+    Digest::SHA1.hexdigest(@fake_token_counter.to_s)
+  end
+  salts   = (1..2).map{ make_fake_token }
+  passwds = salts.map{ |salt| password_digest('monkey', salt) }
+-%>
+
+quentin:
+  id:                        1
+  login:                     quentin
+  email:                     quentin at example.com
+  salt:                      <%= salts[0]   %> # SHA1('0')
+  crypted_password:          <%= passwds[0] %> # 'monkey'
+  created_at:                <%%= 5.days.ago.to_s :db  %>
+  remember_token_expires_at: <%%= 1.days.from_now.to_s %>
+  remember_token:            <%= make_fake_token %>
+<% if options[:include_activation] -%>
+  activation_code:           
+  activated_at:              <%%= 5.days.ago.to_s :db %>
+<% end -%>
+<% if options[:stateful] -%>
+  state:                     active
+<% end -%>
+      
+aaron:
+  id:                        2
+  login:                     aaron
+  email:                     aaron at example.com
+  salt:                      <%= salts[1]   %> # SHA1('1')
+  crypted_password:          <%= passwds[1] %> # 'monkey'
+  created_at:                <%%= 1.days.ago.to_s :db %>
+  remember_token_expires_at: 
+  remember_token:            
+<% if options[:include_activation] -%>
+  activation_code:           <%= make_fake_token %>
+  activated_at:              
+<% end -%>
+<% if options[:stateful] %>
+  state:                     pending
+<% end -%>
+
+
+old_password_holder:
+  id:                        3
+  login:                     old_password_holder
+  email:                     salty_dog at example.com
+  salt:                      7e3041ebc2fc05a40c60028e2c4901a81035d3cd
+  crypted_password:          00742970dc9e6319f8019fd54864d3ea740f04b1 # test
+  created_at:                <%%= 1.days.ago.to_s :db %>
+<% if options[:include_activation] %>
+  activation_code:           
+  activated_at:              <%%= 5.days.ago.to_s :db %>
+<% end %>
+<% if options[:stateful] %>
+  state:                     active<% end %>

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/helpers/users_helper_spec.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/helpers/users_helper_spec.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/helpers/users_helper_spec.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,141 @@
+require File.dirname(__FILE__) + '<%= ('/..'*model_controller_class_nesting_depth) + '/../spec_helper' %>'
+include ApplicationHelper
+include <%= model_controller_class_name %>Helper
+include AuthenticatedTestHelper
+
+describe <%= model_controller_class_name %>Helper do
+  before do
+    @<%= file_name %> = mock_<%= file_name %>
+  end
+  
+  describe "if_authorized" do 
+    it "yields if authorized" do
+      should_receive(:authorized?).with('a','r').and_return(true)
+      if_authorized?('a','r'){|action,resource| [action,resource,'hi'] }.should == ['a','r','hi']
+    end
+    it "does nothing if not authorized" do
+      should_receive(:authorized?).with('a','r').and_return(false)
+      if_authorized?('a','r'){ 'hi' }.should be_nil
+    end
+  end
+  
+  describe "link_to_<%= file_name %>" do
+    it "should give an error on a nil <%= file_name %>" do
+      lambda { link_to_<%= file_name %>(nil) }.should raise_error('Invalid <%= file_name %>')
+    end
+    it "should link to the given <%= file_name %>" do
+      should_receive(:<%= model_controller_routing_name.singularize %>_path).at_least(:once).and_return('/<%= model_controller_file_path %>/1')
+      link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a[href='/<%= model_controller_file_path %>/1']")
+    end
+    it "should use given link text if :content_text is specified" do
+      link_to_<%= file_name %>(@<%= file_name %>, :content_text => 'Hello there!').should have_tag("a", 'Hello there!')
+    end
+    it "should use the login as link text with no :content_method specified" do
+      link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a", 'user_name')
+    end
+    it "should use the name as link text with :content_method => :name" do
+      link_to_<%= file_name %>(@<%= file_name %>, :content_method => :name).should have_tag("a", 'U. Surname')
+    end
+    it "should use the login as title with no :title_method specified" do
+      link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a[title='user_name']")
+    end
+    it "should use the name as link title with :content_method => :name" do
+      link_to_<%= file_name %>(@<%= file_name %>, :title_method => :name).should have_tag("a[title='U. Surname']")
+    end
+    it "should have nickname as a class by default" do
+      link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a.nickname")
+    end
+    it "should take other classes and no longer have the nickname class" do
+      result = link_to_<%= file_name %>(@<%= file_name %>, :class => 'foo bar')
+      result.should have_tag("a.foo")
+      result.should have_tag("a.bar")
+    end
+  end
+
+  describe "link_to_login_with_IP" do
+    it "should link to the login_path" do
+      link_to_login_with_IP().should have_tag("a[href='/login']")
+    end
+    it "should use given link text if :content_text is specified" do
+      link_to_login_with_IP('Hello there!').should have_tag("a", 'Hello there!')
+    end
+    it "should use the login as link text with no :content_method specified" do
+      link_to_login_with_IP().should have_tag("a", '0.0.0.0')
+    end
+    it "should use the ip address as title" do
+      link_to_login_with_IP().should have_tag("a[title='0.0.0.0']")
+    end
+    it "should by default be like school in summer and have no class" do
+      link_to_login_with_IP().should_not have_tag("a.nickname")
+    end
+    it "should have some class if you tell it to" do
+      result = link_to_login_with_IP(nil, :class => 'foo bar')
+      result.should have_tag("a.foo")
+      result.should have_tag("a.bar")
+    end
+    it "should have some class if you tell it to" do
+      result = link_to_login_with_IP(nil, :tag => 'abbr')
+      result.should have_tag("abbr[title='0.0.0.0']")
+    end
+  end
+
+  describe "link_to_current_<%= file_name %>, When logged in" do
+    before do
+      stub!(:current_<%= file_name %>).and_return(@<%= file_name %>)
+    end
+    it "should link to the given <%= file_name %>" do
+      should_receive(:<%= model_controller_routing_name.singularize %>_path).at_least(:once).and_return('/<%= model_controller_file_path %>/1')
+      link_to_current_<%= file_name %>().should have_tag("a[href='/<%= model_controller_file_path %>/1']")
+    end
+    it "should use given link text if :content_text is specified" do
+      link_to_current_<%= file_name %>(:content_text => 'Hello there!').should have_tag("a", 'Hello there!')
+    end
+    it "should use the login as link text with no :content_method specified" do
+      link_to_current_<%= file_name %>().should have_tag("a", 'user_name')
+    end
+    it "should use the name as link text with :content_method => :name" do
+      link_to_current_<%= file_name %>(:content_method => :name).should have_tag("a", 'U. Surname')
+    end
+    it "should use the login as title with no :title_method specified" do
+      link_to_current_<%= file_name %>().should have_tag("a[title='user_name']")
+    end
+    it "should use the name as link title with :content_method => :name" do
+      link_to_current_<%= file_name %>(:title_method => :name).should have_tag("a[title='U. Surname']")
+    end
+    it "should have nickname as a class" do
+      link_to_current_<%= file_name %>().should have_tag("a.nickname")
+    end
+    it "should take other classes and no longer have the nickname class" do
+      result = link_to_current_<%= file_name %>(:class => 'foo bar')
+      result.should have_tag("a.foo")
+      result.should have_tag("a.bar")
+    end
+  end
+
+  describe "link_to_current_<%= file_name %>, When logged out" do
+    before do
+      stub!(:current_<%= file_name %>).and_return(nil)
+    end
+    it "should link to the login_path" do
+      link_to_current_<%= file_name %>().should have_tag("a[href='/login']")
+    end
+    it "should use given link text if :content_text is specified" do
+      link_to_current_<%= file_name %>(:content_text => 'Hello there!').should have_tag("a", 'Hello there!')
+    end
+    it "should use 'not signed in' as link text with no :content_method specified" do
+      link_to_current_<%= file_name %>().should have_tag("a", 'not signed in')
+    end
+    it "should use the ip address as title" do
+      link_to_current_<%= file_name %>().should have_tag("a[title='0.0.0.0']")
+    end
+    it "should by default be like school in summer and have no class" do
+      link_to_current_<%= file_name %>().should_not have_tag("a.nickname")
+    end
+    it "should have some class if you tell it to" do
+      result = link_to_current_<%= file_name %>(:class => 'foo bar')
+      result.should have_tag("a.foo")
+      result.should have_tag("a.bar")
+    end
+  end
+
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/models/user_spec.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/models/user_spec.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/spec/models/user_spec.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,290 @@
+# -*- coding: mule-utf-8 -*-
+require File.dirname(__FILE__) + '<%= ('/..'*model_controller_class_nesting_depth) + '/../spec_helper' %>'
+
+# Be sure to include AuthenticatedTestHelper in spec/spec_helper.rb instead.
+# Then, you can remove it from this and the functional test.
+include AuthenticatedTestHelper
+
+describe <%= class_name %> do
+  fixtures :<%= table_name %>
+
+  describe 'being created' do
+    before do
+      @<%= file_name %> = nil
+      @creating_<%= file_name %> = lambda do
+        @<%= file_name %> = create_<%= file_name %>
+        violated "#{@<%= file_name %>.errors.full_messages.to_sentence}" if @<%= file_name %>.new_record?
+      end
+    end
+    
+    it 'increments <%= class_name %>#count' do
+      @creating_<%= file_name %>.should change(<%= class_name %>, :count).by(1)
+    end
+<% if options[:include_activation] %>
+    it 'initializes #activation_code' do
+      @creating_<%= file_name %>.call
+      @<%= file_name %>.reload
+      @<%= file_name %>.activation_code.should_not be_nil
+    end
+<% end %><% if options[:stateful] %>
+    it 'starts in pending state' do
+      @creating_<%= file_name %>.call
+      @<%= file_name %>.reload
+      @<%= file_name %>.should be_pending
+    end
+<% end %>  end
+
+  #              
+  # Validations
+  #
+ 
+  it 'requires login' do
+    lambda do
+      u = create_<%= file_name %>(:login => nil)
+      u.errors.on(:login).should_not be_nil
+    end.should_not change(<%= class_name %>, :count)
+  end
+
+  describe 'allows legitimate logins:' do
+    ['123', '1234567890_234567890_234567890_234567890', 
+     'hello.-_there at funnychar.com'].each do |login_str|
+      it "'#{login_str}'" do
+        lambda do
+          u = create_<%= file_name %>(:login => login_str)
+          u.errors.on(:login).should     be_nil
+        end.should change(<%= class_name %>, :count).by(1)
+      end
+    end
+  end
+  describe 'disallows illegitimate logins:' do
+    ['12', '1234567890_234567890_234567890_234567890_', "tab\t", "newline\n",
+     "Iñtërnâtiônàlizætiøn hasn't happened to ruby 1.8 yet", 
+     'semicolon;', 'quote"', 'tick\'', 'backtick`', 'percent%', 'plus+', 'space '].each do |login_str|
+      it "'#{login_str}'" do
+        lambda do
+          u = create_<%= file_name %>(:login => login_str)
+          u.errors.on(:login).should_not be_nil
+        end.should_not change(<%= class_name %>, :count)
+      end
+    end
+  end
+
+  it 'requires password' do
+    lambda do
+      u = create_<%= file_name %>(:password => nil)
+      u.errors.on(:password).should_not be_nil
+    end.should_not change(<%= class_name %>, :count)
+  end
+
+  it 'requires password confirmation' do
+    lambda do
+      u = create_<%= file_name %>(:password_confirmation => nil)
+      u.errors.on(:password_confirmation).should_not be_nil
+    end.should_not change(<%= class_name %>, :count)
+  end
+
+  it 'requires email' do
+    lambda do
+      u = create_<%= file_name %>(:email => nil)
+      u.errors.on(:email).should_not be_nil
+    end.should_not change(<%= class_name %>, :count)
+  end
+
+  describe 'allows legitimate emails:' do
+    ['foo at bar.com', 'foo at newskool-tld.museum', 'foo at twoletter-tld.de', 'foo at nonexistant-tld.qq',
+     'r at a.wk', '1234567890-234567890-234567890-234567890-234567890-234567890-234567890-234567890-234567890 at gmail.com',
+     'hello.-_there at funnychar.com', 'uucp%addr at gmail.com', 'hello+routing-str at gmail.com',
+     'domain at can.haz.many.sub.doma.in', 
+    ].each do |email_str|
+      it "'#{email_str}'" do
+        lambda do
+          u = create_<%= file_name %>(:email => email_str)
+          u.errors.on(:email).should     be_nil
+        end.should change(<%= class_name %>, :count).by(1)
+      end
+    end
+  end
+  describe 'disallows illegitimate emails' do
+    ['!!@nobadchars.com', 'foo at no-rep-dots..com', 'foo at badtld.xxx', 'foo at toolongtld.abcdefg',
+     'Iñtërnâtiônàlizætiøn at hasnt.happened.to.email', 'need.domain.and.tld at de', "tab\t", "newline\n",
+     'r at .wk', '1234567890-234567890-234567890-234567890-234567890-234567890-234567890-234567890-234567890 at gmail2.com',
+     # these are technically allowed but not seen in practice:
+     'uucp!addr at gmail.com', 'semicolon;@gmail.com', 'quote"@gmail.com', 'tick\'@gmail.com', 'backtick`@gmail.com', 'space @gmail.com', 'bracket<@gmail.com', 'bracket>@gmail.com'
+    ].each do |email_str|
+      it "'#{email_str}'" do
+        lambda do
+          u = create_<%= file_name %>(:email => email_str)
+          u.errors.on(:email).should_not be_nil
+        end.should_not change(<%= class_name %>, :count)
+      end
+    end
+  end
+
+  describe 'allows legitimate names:' do
+    ['Andre The Giant (7\'4", 520 lb.) -- has a posse', 
+     '', '1234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890',
+    ].each do |name_str|
+      it "'#{name_str}'" do
+        lambda do
+          u = create_<%= file_name %>(:name => name_str)
+          u.errors.on(:name).should     be_nil
+        end.should change(<%= class_name %>, :count).by(1)
+      end
+    end
+  end
+  describe "disallows illegitimate names" do
+    ["tab\t", "newline\n",
+     '1234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890_',
+     ].each do |name_str|
+      it "'#{name_str}'" do
+        lambda do
+          u = create_<%= file_name %>(:name => name_str)
+          u.errors.on(:name).should_not be_nil
+        end.should_not change(<%= class_name %>, :count)
+      end
+    end
+  end
+
+  it 'resets password' do
+    <%= table_name %>(:quentin).update_attributes(:password => 'new password', :password_confirmation => 'new password')
+    <%= class_name %>.authenticate('quentin', 'new password').should == <%= table_name %>(:quentin)
+  end
+
+  it 'does not rehash password' do
+    <%= table_name %>(:quentin).update_attributes(:login => 'quentin2')
+    <%= class_name %>.authenticate('quentin2', 'monkey').should == <%= table_name %>(:quentin)
+  end
+
+  #
+  # Authentication
+  #
+
+  it 'authenticates <%= file_name %>' do
+    <%= class_name %>.authenticate('quentin', 'monkey').should == <%= table_name %>(:quentin)
+  end
+
+  it "doesn't authenticates <%= file_name %> with bad password" do
+    <%= class_name %>.authenticate('quentin', 'monkey').should == <%= table_name %>(:quentin)
+  end
+
+ if REST_AUTH_SITE_KEY.blank? 
+   # old-school passwords
+   it "authenticates a user against a hard-coded old-style password" do
+     <%= class_name %>.authenticate('old_password_holder', 'test').should == <%= table_name %>(:old_password_holder)
+   end
+ else
+   it "doesn't authenticate a user against a hard-coded old-style password" do
+     <%= class_name %>.authenticate('old_password_holder', 'test').should be_nil
+   end
+
+   # New installs should bump this up and set REST_AUTH_DIGEST_STRETCHES to give a 10ms encrypt time or so
+   desired_encryption_expensiveness_ms = 0.1
+   it "takes longer than #{desired_encryption_expensiveness_ms}ms to encrypt a password" do
+     test_reps = 100
+     start_time = Time.now; test_reps.times{ <%= class_name %>.authenticate('quentin', 'monkey'+rand.to_s) }; end_time   = Time.now
+     auth_time_ms = 1000 * (end_time - start_time)/test_reps
+     auth_time_ms.should > desired_encryption_expensiveness_ms
+   end
+ end
+
+  #
+  # Authentication
+  #
+
+  it 'sets remember token' do
+    <%= table_name %>(:quentin).remember_me
+    <%= table_name %>(:quentin).remember_token.should_not be_nil
+    <%= table_name %>(:quentin).remember_token_expires_at.should_not be_nil
+  end
+
+  it 'unsets remember token' do
+    <%= table_name %>(:quentin).remember_me
+    <%= table_name %>(:quentin).remember_token.should_not be_nil
+    <%= table_name %>(:quentin).forget_me
+    <%= table_name %>(:quentin).remember_token.should be_nil
+  end
+
+  it 'remembers me for one week' do
+    before = 1.week.from_now.utc
+    <%= table_name %>(:quentin).remember_me_for 1.week
+    after = 1.week.from_now.utc
+    <%= table_name %>(:quentin).remember_token.should_not be_nil
+    <%= table_name %>(:quentin).remember_token_expires_at.should_not be_nil
+    <%= table_name %>(:quentin).remember_token_expires_at.between?(before, after).should be_true
+  end
+
+  it 'remembers me until one week' do
+    time = 1.week.from_now.utc
+    <%= table_name %>(:quentin).remember_me_until time
+    <%= table_name %>(:quentin).remember_token.should_not be_nil
+    <%= table_name %>(:quentin).remember_token_expires_at.should_not be_nil
+    <%= table_name %>(:quentin).remember_token_expires_at.should == time
+  end
+
+  it 'remembers me default two weeks' do
+    before = 2.weeks.from_now.utc
+    <%= table_name %>(:quentin).remember_me
+    after = 2.weeks.from_now.utc
+    <%= table_name %>(:quentin).remember_token.should_not be_nil
+    <%= table_name %>(:quentin).remember_token_expires_at.should_not be_nil
+    <%= table_name %>(:quentin).remember_token_expires_at.between?(before, after).should be_true
+  end
+<% if options[:stateful] %>
+  it 'registers passive <%= file_name %>' do
+    <%= file_name %> = create_<%= file_name %>(:password => nil, :password_confirmation => nil)
+    <%= file_name %>.should be_passive
+    <%= file_name %>.update_attributes(:password => 'new password', :password_confirmation => 'new password')
+    <%= file_name %>.register!
+    <%= file_name %>.should be_pending
+  end
+
+  it 'suspends <%= file_name %>' do
+    <%= table_name %>(:quentin).suspend!
+    <%= table_name %>(:quentin).should be_suspended
+  end
+
+  it 'does not authenticate suspended <%= file_name %>' do
+    <%= table_name %>(:quentin).suspend!
+    <%= class_name %>.authenticate('quentin', 'monkey').should_not == <%= table_name %>(:quentin)
+  end
+
+  it 'deletes <%= file_name %>' do
+    <%= table_name %>(:quentin).deleted_at.should be_nil
+    <%= table_name %>(:quentin).delete!
+    <%= table_name %>(:quentin).deleted_at.should_not be_nil
+    <%= table_name %>(:quentin).should be_deleted
+  end
+
+  describe "being unsuspended" do
+    fixtures :<%= table_name %>
+
+    before do
+      @<%= file_name %> = <%= table_name %>(:quentin)
+      @<%= file_name %>.suspend!
+    end
+    
+    it 'reverts to active state' do
+      @<%= file_name %>.unsuspend!
+      @<%= file_name %>.should be_active
+    end
+    
+    it 'reverts to passive state if activation_code and activated_at are nil' do
+      <%= class_name %>.update_all :activation_code => nil, :activated_at => nil
+      @<%= file_name %>.reload.unsuspend!
+      @<%= file_name %>.should be_passive
+    end
+    
+    it 'reverts to pending state if activation_code is set and activated_at is nil' do
+      <%= class_name %>.update_all :activation_code => 'foo-bar', :activated_at => nil
+      @<%= file_name %>.reload.unsuspend!
+      @<%= file_name %>.should be_pending
+    end
+  end
+<% end %>
+protected
+  def create_<%= file_name %>(options = {})
+    record = <%= class_name %>.new({ :login => 'quire', :email => 'quire at example.com', :password => 'quire69', :password_confirmation => 'quire69' }.merge(options))
+    record.<% if options[:stateful] %>register! if record.valid?<% else %>save<% end %>
+    record
+  end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/rest_auth_stories.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/rest_auth_stories.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/rest_auth_stories.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,22 @@
+#!/usr/bin/env ruby
+ENV["RAILS_ENV"] = "test"
+require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
+require 'spec/rails/story_adapter'
+require 'spec/story'
+require File.expand_path(File.dirname(__FILE__) + "/rest_auth_stories_helper.rb")
+
+# Make visible for testing
+ApplicationController.send(:public, :logged_in?, :current_user, :authorized?)
+
+this_dir = File.dirname(__FILE__)
+Dir[File.join(this_dir, "steps/*.rb")].each do |file|
+  puts file.to_s
+  require file
+end
+
+with_steps_for :ra_navigation, :ra_response, :ra_resource, :<%= file_name %> do
+  story_files = Dir[File.join(this_dir, "<%= table_name %>", '*.story')]
+  story_files.each do |file|
+    run file, :type => RailsStory 
+  end
+end


Property changes on: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/rest_auth_stories.rb
___________________________________________________________________
Name: svn:executable
   + *

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/rest_auth_stories_helper.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/rest_auth_stories_helper.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/rest_auth_stories_helper.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,81 @@
+# If you have a global stories helper, move this line there:
+include AuthenticatedTestHelper
+
+# Most of the below came out of code from Ben Mabey
+# http://www.benmabey.com/2008/02/04/rspec-plain-text-stories-webrat-chunky-bacon/
+
+# These allow exceptions to come through as opposed to being caught and hvaing non-helpful responses returned.
+ActionController::Base.class_eval do
+  def perform_action
+    perform_action_without_rescue
+  end
+end
+Dispatcher.class_eval do
+  def self.failsafe_response(output, status, exception = nil)
+    raise exception
+  end
+end
+
+#
+# Sugar for turning a story's attribute list into list, array, etc.
+#
+module ToFooFromStory
+  def ToFooFromStory.fix_key key
+    key.downcase.gsub(/\s+/, '_')
+  end
+  def ToFooFromStory.fix_value value
+    return '' if !value
+    value.strip!
+    case 
+    when value =~ /^'(.*)'$/    then value = $1
+    when value =~ /^"(.*)"$/    then value = $1
+    when value == 'nil!'        then value = nil
+    when value == 'non-nil!'    then value = be_nil
+    when value =~ /^#\{(.*)\}$/ then value = eval($1)
+    end
+    value
+  end
+  # Converts a key: value list found in the steps into a hash.  
+  # Example:
+  #   ISBN: '0967539854' and comment: 'I love this book' and Quality rating: '4'
+  #   # => {"quality_rating"=>"4", "isbn"=>"0967539854", "comment"=>"I love this book"}
+  def to_hash_from_story
+    hsh = self.split(/,? and |, /).inject({}) do |hash_so_far, key_value|
+      key, value = key_value.split(":")
+      if !value then warn "Couldn't understand story '#{self}': only understood up to the part '#{hash_so_far.to_yaml}'" end
+      hash_so_far.merge(ToFooFromStory::fix_key(key) => ToFooFromStory::fix_value(value))
+    end
+  end
+  # Coverts an attribute list found in the steps into an array
+  # Example:
+  #   login, email, updated_at, and gravatar
+  #   # => ['login', 'email', 'updated_at', 'gravatar']
+  def to_array_from_story
+    self.split(/,? and |, /).map do |value|
+      ToFooFromStory::fix_value(value)
+    end
+  end
+end
+class String
+  include ToFooFromStory        
+end
+
+def instantize(string)
+  instance_variable_get("@#{string}")
+end
+
+#
+# Spew response onto screen -- painful but scrolling >> debugger
+#
+def dump_response
+  # note that @request and @template won't to_yaml and that @session includes @cgi
+  response_methods = response.instance_variables         - ['@request', '@template', '@cgi']
+  request_methods  = response.request.instance_variables - ['@session_options_with_string_keys', '@cgi', '@session']
+  response_methods.map!{|attr| attr.gsub(/^@/,'')}.sort!
+  request_methods.map!{ |attr| attr.gsub(/^@/,'')}.sort!
+  puts '', '*' * 75, 
+    response.instance_values.slice(*response_methods).to_yaml,
+    "*" * 75, '',
+    response.request.instance_values.slice(*request_methods).to_yaml,
+    "*" * 75, ''  
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/ra_navigation_steps.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/ra_navigation_steps.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/ra_navigation_steps.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,49 @@
+#
+# Where to go
+#
+steps_for(:ra_navigation) do
+  #
+  # GET
+  # Go to a given page. 
+  When "$actor goes to $path" do |actor, path|
+    case path
+    when 'the home page' then get '/'
+    else                      get path
+    end
+  end
+
+  # POST -- Ex:
+  #   When she creates a book with ISBN: '0967539854' and comment: 'I love this book' and rating: '4'
+  #   When she creates a singular session with login: 'reggie' and password: 'i_haxxor_joo'
+  # Since I'm not smrt enough to do it right, explicitly specify singular resources
+  When %r{$actor creates an? $resource with $attributes} do |actor, resource, attributes|
+    attributes = attributes.to_hash_from_story
+    if resource =~ /singular (\w+)/
+      resource = $1.downcase.singularize
+      post "/#{resource}", attributes
+    else 
+      post "/#{resource.downcase.pluralize}", { resource.downcase.singularize => attributes }
+    end
+  end
+
+  # PUT 
+  When %r{$actor asks to update '$resource' with $attributes} do |_, resource, attributes|
+    attributes = attributes.to_hash_from_story
+    put "#{resource}", attributes
+    dump_response
+  end
+
+  # DELETE -- Slap together the POST-form-as-fake-HTTP-DELETE submission
+  When %r{$actor asks to delete '$resource'} do |_, resource|
+    post "/#{resource.downcase.pluralize}", { :_method => :delete }
+    dump_response
+  end
+  
+  
+  # Redirect --
+  #   Rather than coding in get/get_via_redirect's and past/p_v_r's,
+  #   let's just demand that in the story itself.
+  When "$actor follows that redirect!" do |actor|
+    follow_redirect!
+  end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/ra_resource_steps.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/ra_resource_steps.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/ra_resource_steps.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,179 @@
+# The flexible code for resource testing came out of code from Ben Mabey
+# http://www.benmabey.com/2008/02/04/rspec-plain-text-stories-webrat-chunky-bacon/
+steps_for(:ra_resource) do
+  #
+  # Construct resources
+  #
+  
+  #
+  # Build a resource as described, store it as an @instance variable. Ex:
+  #   "Given a <%= file_name %> with login: 'mojojojo'" 
+  # produces a <%= class_name %> instance stored in @<%= file_name %> with 'mojojojo' as its login
+  # attribute.
+  #
+  Given "a $resource instance with $attributes" do |resource, attributes|
+    klass, instance, attributes = parse_resource_args resource, attributes
+    instance = klass.new(attributes)
+    instance.save!
+    find_resource(resource, attributes).should_not be_nil
+    keep_instance! resource, instance
+  end
+  
+  #
+  # Stuff attributes into a preexisting @resource
+  #   "And the <%= file_name %> has thac0: 3"
+  # takes the earlier-defined @<%= file_name %> instance and sets its thac0 to '3'.
+  #
+  Given "the $resource has $attributes" do |resource, attributes|
+    klass, instance, attributes = parse_resource_args resource, attributes
+    attributes.each do |attr, val|
+      instance.send("#{attr}=", val)
+    end
+    instance.save!
+    find_resource(resource, attributes).should_not be_nil
+    keep_instance! resource, instance 
+  end
+  
+  #
+  # Destroy all for this resource
+  #
+  Given "no $resource with $attr: '$val' exists" do |resource, attr, val|
+    klass, instance = parse_resource_args resource
+    klass.destroy_all(attr.to_sym => val)
+    instance = find_resource resource, attr.to_sym => val
+    instance.should be_nil
+    keep_instance! resource, instance
+  end
+
+  #
+  # Then's for resources
+  #
+  
+  # Resource like this DOES exist
+  Then %r{an? $resource with $attributes should exist} do |resource, attributes|
+    instance = find_resource resource, attributes
+    instance.should_not be_nil
+    keep_instance! resource, instance
+  end
+  # Resource like this DOES NOT exist
+  Then %r{no $resource with $attributes should exist} do |resource, attributes|
+    instance = find_resource resource, attributes
+    instance.should be_nil
+  end
+
+  # Resource has attributes with given values
+  Then  "the $resource should have $attributes" do |resource, attributes|
+    klass, instance, attributes = parse_resource_args resource, attributes
+    attributes.each do |attr, val|
+      instance.send(attr).should == val
+    end
+  end
+  # Resource attributes should / should not be nil
+  Then  "the $resource's $attr should be nil" do |resource, attr|
+    klass, instance = parse_resource_args resource
+    instance.send(attr).should be_nil
+  end
+  Then  "the $resource's $attr should not be nil" do |resource, attr|
+    klass, instance = parse_resource_args resource
+    instance.send(attr).should_not be_nil
+  end
+
+  #
+  # Bank each of the @resource's listed attributes for later.
+  #
+  Given "we try hard to remember the $resource's $attributes" do |resource, attributes|
+    attributes = attributes.to_array_from_story
+    attributes.each do |attr|
+      memorize_resource_value resource, attr
+    end
+  end
+  #
+  # Bank each of the @resource's listed attributes for later.
+  #
+  Given "we don't remember anything about the past" do 
+    memorize_forget_all!
+  end
+
+  #
+  # Compare @resource.attr to its earlier-memorized value. 
+  # Specify ' using method_name' (abs, to_s, &c) to coerce before comparing.
+  # For important and mysterious reasons, timestamps want to_i or to_s.
+  #
+  Then %r{the $resource\'s $attribute should stay the same(?: under $func)?} do |resource, attr, func|
+    klass, instance = parse_resource_args resource
+    # Get the values
+    old_value = recall_resource_value(resource, attr)
+    new_value = instance.send(attr)
+    # Transform each value, maybe, using value.func
+    if func then new_value = new_value.send(func); old_value = old_value.send(func) end
+    # Compare
+    old_value.should eql(new_value)
+  end
+
+  #
+  # Look for each for the given attributes in the page's text
+  #
+  Then "page should have the $resource's $attributes" do |resource, attributes|
+    actual_resource = instantize(resource)
+    attributes.split(/, and |, /).each do |attribute|
+      response.should have_text(/#{actual_resource.send(attribute.strip.gsub(" ","_"))}/)
+    end
+  end
+  
+end
+
+#
+# Turn a resource name and a to_hash_from_story string like
+#   "attr: 'value', attr2: 'value2', ... , and attrN: 'valueN'"
+# into 
+#   * klass      -- the class matching that Resource
+#   * instance   -- the possibly-preexisting local instance value @resource
+#   * attributes -- a hash matching the given attribute-list string
+# 
+def parse_resource_args resource, attributes=nil
+  instance   = instantize resource
+  klass      = resource.classify.constantize
+  attributes = attributes.to_hash_from_story if attributes
+  [klass, instance, attributes]
+end
+
+#
+# Given a class name 'resource' and a hash of conditsion, find a model 
+#
+def find_resource resource, conditions
+  klass, instance = parse_resource_args resource
+  conditions = conditions.to_hash_from_story unless (conditions.is_a? Hash)
+  klass.find(:first, :conditions => conditions)
+end
+
+#
+# Simple, brittle, useful: store the given resource's attribute
+# so we can compare it later.
+#
+def memorize_resource_value resource, attr
+  klass, instance = parse_resource_args resource
+  value = instance.send(attr)
+  @_memorized ||= {}
+  @_memorized[resource] ||= {}
+  @_memorized[resource][attr] = value
+  value
+end
+def recall_resource_value resource, attr
+  @_memorized[resource][attr]
+end
+def memorize_forget_all!
+  @_memorized = {}
+end
+
+#
+# Keep the object around in a local instance variable @resource.
+#
+# So, for instance,
+#   klass, instance = parse_resource_args '<%= file_name %>'
+#   instance = klass.new({login => 'me', password => 'monkey', ...})
+#   keep_instance! resource, instance
+# keeps the just-constructed <%= class_name %> model in the @<%= file_name %> instance variable.
+#
+def keep_instance! resource, object
+  instance_variable_set("@#{resource}", object)
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/ra_response_steps.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/ra_response_steps.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/ra_response_steps.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,171 @@
+#
+# What you should see when you get there
+#
+
+steps_for(:ra_response) do  
+  #
+  # Destinations.  Ex:
+  #   She should be at the new kids page
+  #   Tarkin should be at the destroy alderaan page 
+  #   The visitor should be at the '/lolcats/download' form
+  #   The visitor should be redirected to '/hi/mom'
+  #
+  # It doesn't know anything about actual routes -- it just 
+  # feeds its output to render_template or redirect_to
+  #
+  Then "$actor should be at $path" do |_, path|
+    response.should render_template(grok_path(path))
+  end
+
+  Then "$actor should be redirected to $path" do |_, path|
+    response.should redirect_to(grok_path(path))
+  end  
+
+  Then "the page should look AWESOME" do
+    response.should have_tag('head>title')
+    response.should have_tag('h1')
+    # response.should be_valid_xhtml
+  end
+  
+  #
+  # Tags 
+  #
+  
+  Then "the page should contain '$text'" do |_, text|
+    response.should have_text(/#{text}/)
+  end
+  
+  # please note: this enforces the use of a <label> field
+  Then "$actor should see a <$container> containing a $attributes" do |_, container, attributes|
+    attributes = attributes.to_hash_from_story
+    response.should have_tag(container) do
+      attributes.each do |tag, label|
+        case tag
+        when "textfield" then with_tag "input[type='text']";     with_tag("label", label)
+        when "password"  then with_tag "input[type='password']"; with_tag("label", label)
+        when "submit"    then with_tag "input[type='submit'][value='#{label}']"
+        else with_tag tag, label
+        end
+      end
+    end
+  end
+
+  #
+  # Session, cookie variables
+  #
+  Then "$actor $token cookie should include $attrlist" do |_, token, attrlist|
+    attrlist = attrlist.to_array_from_story
+    cookies.include?(token).should be_true
+    attrlist.each do |val|
+      cookies[token].include?(val).should be_true
+    end
+  end
+  
+  Then "$actor $token cookie should exist but not include $attrlist" do |_, token, attrlist|
+    attrlist = attrlist.to_array_from_story
+    cookies.include?(token).should be_true
+    puts [cookies, attrlist, token].to_yaml
+    attrlist.each do |val|
+      cookies[token].include?(val).should_not be_true
+    end
+  end
+
+  Then "$actor should have $an $token cookie" do |_, _, token|
+    cookies[token].should_not be_blank
+  end
+  Then "$actor should not have $an $token cookie" do |_, _, token|
+    cookies[token].should be_blank
+  end
+
+  Given "$actor has $an cookie jar with $attributes" do |_, _, attributes|
+    attributes = attributes.to_hash_from_story
+    attributes.each do |attr, val|
+      cookies[attr] = val
+    end
+  end
+  Given "$actor session store has no $attrlist" do |_, attrlist|
+    attrlist = attrlist.to_array_from_story
+    attrlist.each do |attr|
+      # Note that the comparison passes through 'to_s'
+      session[attr.to_sym] = nil
+    end
+  end
+  
+  Then "$actor session store should have $attributes" do |_, attributes|
+    attributes = attributes.to_hash_from_story
+    attributes.each do |attr, val|
+      # Note that the comparison passes through 'to_s'
+      session[attr.to_sym].to_s.should eql(val)
+    end
+  end
+  
+  Then "$actor session store should not have $attrlist" do |_, attrlist|
+    attrlist = attrlist.to_array_from_story
+    attrlist.each do |attr|
+      session[attr.to_sym].blank?.should be_true
+    end
+  end
+
+  #
+  # Flash messages
+  #
+  
+  Then "$actor should see $an $notice message '$message'" do |_, _, notice, message|
+    response.should have_flash(notice, %r{#{message}})
+  end
+  
+  Then "$actor should not see $an $notice message '$message'" do |_, _, notice, message|
+    response.should_not have_flash(notice, %r{#{message}})
+  end
+  
+  Then "$actor should see no messages" do |_|
+    ['error', 'warning', 'notice'].each do |notice|
+      response.should_not have_flash(notice)
+    end
+  end
+
+  RE_POLITENESS = /(?:please|sorry|thank(?:s| you))/i
+  Then %r{we should be polite about it} do 
+    response.should have_tag("div.error,div.notice", RE_POLITENESS)
+  end
+  Then %r{we should not even be polite about it} do 
+    response.should_not have_tag("div.error,div.notice", RE_POLITENESS)
+  end
+  
+  #
+  # Resource's attributes
+  # 
+  # "Then page should have the $resource's $attributes" is in resource_steps
+  
+  # helpful debug step
+  Then "we dump the response" do
+    dump_response
+  end  
+end
+
+
+def have_flash notice, *args
+  have_tag("div.#{notice}", *args)
+end
+
+RE_PRETTY_RESOURCE = /the (index|show|new|create|edit|update|destroy) (\w+) (page|form)/i
+RE_THE_FOO_PAGE    = /the '?([^']*)'? (page|form)/i
+RE_QUOTED_PATH     = /^'([^']*)'$/i
+def grok_path path
+  path.gsub(/\s+again$/,'') # strip trailing ' again'
+  case
+  when path == 'the home page'    then dest = '/'
+  when path =~ RE_PRETTY_RESOURCE then dest = template_for $1, $2
+  when path =~ RE_THE_FOO_PAGE    then dest = $1
+  when path =~ RE_QUOTED_PATH     then dest = $1
+  else                                 dest = path
+  end
+  dest
+end
+
+# turns 'new', 'road bikes' into 'road_bikes/new'
+# note that it's "action resource"
+def template_for(action, resource)
+  "#{resource.gsub(" ","_")}/#{action}"
+end
+

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/user_steps.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/user_steps.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/steps/user_steps.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,153 @@
+require File.dirname(__FILE__) + '/../helper'
+
+RE_<%= file_name.capitalize %>      = %r{(?:(?:the )? *(\w+) *)}
+RE_<%= file_name.capitalize %>_TYPE = %r{(?: *(\w+)? *)}
+steps_for(:<%= file_name %>) do
+
+  #
+  # Setting
+  #
+  
+  Given "an anonymous <%= file_name %>" do 
+    log_out!
+  end
+
+  Given "$an $<%= file_name %>_type <%= file_name %> with $attributes" do |_, <%= file_name %>_type, attributes|
+    create_<%= file_name %>! <%= file_name %>_type, attributes.to_hash_from_story
+  end
+  
+  Given "$an $<%= file_name %>_type <%= file_name %> named '$login'" do |_, <%= file_name %>_type, login|
+    create_<%= file_name %>! <%= file_name %>_type, named_<%= file_name %>(login)
+  end
+  
+  Given "$an $<%= file_name %>_type <%= file_name %> logged in as '$login'" do |_, <%= file_name %>_type, login|
+    create_<%= file_name %>! <%= file_name %>_type, named_<%= file_name %>(login)
+    log_in_<%= file_name %>!
+  end
+  
+  Given "$actor is logged in" do |_, login|
+    log_in_<%= file_name %>! @<%= file_name %>_params || named_<%= file_name %>(login)
+  end
+  
+  Given "there is no $<%= file_name %>_type <%= file_name %> named '$login'" do |_, login|
+    @<%= file_name %> = <%= class_name %>.find_by_login(login)
+    @<%= file_name %>.destroy! if @<%= file_name %>
+    @<%= file_name %>.should be_nil
+  end
+  
+  #
+  # Actions
+  #
+  When "$actor logs out" do 
+    log_out
+  end
+
+  When "$actor registers an account as the preloaded '$login'" do |_, login|
+    <%= file_name %> = named_<%= file_name %>(login)
+    <%= file_name %>['password_confirmation'] = <%= file_name %>['password']
+    create_<%= file_name %> <%= file_name %>
+  end
+
+  When "$actor registers an account with $attributes" do |_, attributes|
+    create_<%= file_name %> attributes.to_hash_from_story
+  end
+<% if options[:include_activation] %>  
+  When "$actor activates with activation code $attributes" do |_, activation_code|
+    activation_code = '' if activation_code == 'that is blank'
+    activate 
+  end<% end %>  
+
+  When "$actor logs in with $attributes" do |_, attributes|
+    log_in_<%= file_name %> attributes.to_hash_from_story
+  end
+  
+  #
+  # Result
+  #
+  Then "$actor should be invited to sign in" do |_|
+    response.should render_template('/<%= controller_file_path %>/new')
+  end
+  
+  Then "$actor should not be logged in" do |_|
+    controller.logged_in?.should_not be_true
+  end
+    
+  Then "$login should be logged in" do |login|
+    controller.logged_in?.should be_true
+    controller.current_<%= file_name %>.should === @<%= file_name %>
+    controller.current_<%= file_name %>.login.should == login
+  end
+    
+end
+
+def named_<%= file_name %> login
+  <%= file_name %>_params = {
+    'admin'   => {'id' => 1, 'login' => 'addie', 'password' => '1234addie', 'email' => 'admin at example.com',       },
+    'oona'    => {          'login' => 'oona',   'password' => '1234oona',  'email' => 'unactivated at example.com'},
+    'reggie'  => {          'login' => 'reggie', 'password' => 'monkey',    'email' => 'registered at example.com' },
+    }
+  <%= file_name %>_params[login.downcase]
+end
+
+#
+# <%= class_name %> account actions.
+#
+# The ! methods are 'just get the job done'.  It's true, they do some testing of
+# their own -- thus un-DRY'ing tests that do and should live in the <%= file_name %> account
+# stories -- but the repetition is ultimately important so that a faulty test setup
+# fails early.  
+#
+
+def log_out 
+  get '/<%= controller_file_path %>/destroy'
+end
+
+def log_out!
+  log_out
+  response.should redirect_to('/')
+  follow_redirect!
+end
+
+def create_<%= file_name %>(<%= file_name %>_params={})
+  @<%= file_name %>_params       ||= <%= file_name %>_params
+  post "/<%= model_controller_file_path %>", :<%= file_name %> => <%= file_name %>_params
+  @<%= file_name %> = <%= class_name %>.find_by_login(<%= file_name %>_params['login'])
+end
+
+def create_<%= file_name %>!(<%= file_name %>_type, <%= file_name %>_params)
+  <%= file_name %>_params['password_confirmation'] ||= <%= file_name %>_params['password'] ||= <%= file_name %>_params['password']
+  create_<%= file_name %> <%= file_name %>_params
+  response.should redirect_to('/')
+  follow_redirect!
+<% if options[:include_activation] %> 
+  # fix the <%= file_name %>'s activation status
+  activate_<%= file_name %>! if <%= file_name %>_type == 'activated'<% end %>
+end
+
+<% if options[:include_activation] %> 
+def activate_<%= file_name %> activation_code=nil
+  activation_code = @<%= file_name %>.activation_code if activation_code.nil?
+  get "/activate/#{activation_code}"
+end
+
+def activate_<%= file_name %>! *args
+  activate_<%= file_name %> *args
+  response.should redirect_to('/login')
+  follow_redirect!
+  response.should have_flash("notice", /Signup complete!/)
+end<% end %>
+
+def log_in_<%= file_name %> <%= file_name %>_params=nil
+  @<%= file_name %>_params ||= <%= file_name %>_params
+  <%= file_name %>_params  ||= @<%= file_name %>_params
+  post "/<%= controller_routing_path %>", <%= file_name %>_params
+  @<%= file_name %> = <%= class_name %>.find_by_login(<%= file_name %>_params['login'])
+  controller.current_<%= file_name %>
+end
+
+def log_in_<%= file_name %>! *args
+  log_in_<%= file_name %> *args
+  response.should redirect_to('/')
+  follow_redirect!
+  response.should have_flash("notice", /Logged in successfully/)
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/users/accounts.story
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/users/accounts.story	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/users/accounts.story	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,186 @@
+Visitors should be in control of creating an account and of proving their
+essential humanity/accountability or whatever it is people think the
+id-validation does.  We should be fairly skeptical about this process, as the
+identity+trust chain starts here.
+
+Story: Creating an account
+  As an anonymous <%= file_name %>
+  I want to be able to create an account
+  So that I can be one of the cool kids
+
+  #
+  # Account Creation: Get entry form
+  #
+  Scenario: Anonymous <%= file_name %> can start creating an account
+    Given an anonymous <%= file_name %>
+    When  she goes to /signup
+    Then  she should be at the '<%= model_controller_routing_path %>/new' page
+     And  the page should look AWESOME
+     And  she should see a <form> containing a textfield: Login, textfield: Email, password: Password, password: 'Confirm Password', submit: 'Sign up'
+
+  #
+  # Account Creation
+  #
+  Scenario: Anonymous <%= file_name %> can create an account
+    Given an anonymous <%= file_name %>
+     And  no <%= file_name %> with login: 'Oona' exists
+    When  she registers an account as the preloaded 'Oona'
+    Then  she should be redirected to the home page
+    When  she follows that redirect!
+    Then  she should see a notice message 'Thanks for signing up!'
+     And  a <%= file_name %> with login: 'oona' should exist
+     And  the <%= file_name %> should have login: 'oona', and email: 'unactivated at example.com'
+<% if options[:include_activation] %>
+     And  the <%= file_name %>'s activation_code should not be nil
+     And  the <%= file_name %>'s activated_at    should     be nil
+     And  she should not be logged in
+<% else %>
+     And  oona should be logged in
+<% end %>
+
+  #
+  # Account Creation Failure: Account exists
+  #
+<% if options[:include_activation] %>
+  Scenario: Anonymous <%= file_name %> can not create an account replacing a non-activated account
+    Given an anonymous <%= file_name %>
+     And  a registered <%= file_name %> named 'Reggie'
+     And  the <%= file_name %> has activation_code: 'activate_me', activated_at: nil! 
+     And  we try hard to remember the <%= file_name %>'s updated_at, and created_at
+    When  she registers an account with login: 'reggie', password: 'monkey', and email: 'different at example.com'
+    Then  she should be at the '<%= model_controller_routing_path %>/new' page
+     And  she should     see an errorExplanation message 'Login has already been taken'
+     And  she should not see an errorExplanation message 'Email has already been taken'
+     And  a <%= file_name %> with login: 'reggie' should exist
+     And  the <%= file_name %> should have email: 'registered at example.com'
+     And  the <%= file_name %>'s activation_code should not be nil
+     And  the <%= file_name %>'s activated_at    should     be nil
+     And  the <%= file_name %>'s created_at should stay the same under to_s
+     And  the <%= file_name %>'s updated_at should stay the same under to_s
+     And  she should not be logged in<% end %>
+     
+  Scenario: Anonymous <%= file_name %> can not create an account replacing an activated account
+    Given an anonymous <%= file_name %>
+     And  an activated <%= file_name %> named 'Reggie'
+     And  we try hard to remember the <%= file_name %>'s updated_at, and created_at
+    When  she registers an account with login: 'reggie', password: 'monkey', and email: 'reggie at example.com'
+    Then  she should be at the '<%= model_controller_routing_path %>/new' page
+     And  she should     see an errorExplanation message 'Login has already been taken'
+     And  she should not see an errorExplanation message 'Email has already been taken'
+     And  a <%= file_name %> with login: 'reggie' should exist
+     And  the <%= file_name %> should have email: 'registered at example.com'
+<% if options[:include_activation] %>
+     And  the <%= file_name %>'s activation_code should     be nil
+     And  the <%= file_name %>'s activated_at    should not be nil<% end %>
+     And  the <%= file_name %>'s created_at should stay the same under to_s
+     And  the <%= file_name %>'s updated_at should stay the same under to_s
+     And  she should not be logged in
+
+  #
+  # Account Creation Failure: Incomplete input
+  #
+  Scenario: Anonymous <%= file_name %> can not create an account with incomplete or incorrect input
+    Given an anonymous <%= file_name %>
+     And  no <%= file_name %> with login: 'Oona' exists
+    When  she registers an account with login: '',     password: 'monkey', password_confirmation: 'monkey' and email: 'unactivated at example.com'
+    Then  she should be at the '<%= model_controller_routing_path %>/new' page
+     And  she should     see an errorExplanation message 'Login can't be blank'
+     And  no <%= file_name %> with login: 'oona' should exist
+     
+  Scenario: Anonymous <%= file_name %> can not create an account with no password
+    Given an anonymous <%= file_name %>
+     And  no <%= file_name %> with login: 'Oona' exists
+    When  she registers an account with login: 'oona', password: '',       password_confirmation: 'monkey' and email: 'unactivated at example.com'
+    Then  she should be at the '<%= model_controller_routing_path %>/new' page
+     And  she should     see an errorExplanation message 'Password can't be blank'
+     And  no <%= file_name %> with login: 'oona' should exist
+     
+  Scenario: Anonymous <%= file_name %> can not create an account with no password_confirmation
+    Given an anonymous <%= file_name %>
+     And  no <%= file_name %> with login: 'Oona' exists
+    When  she registers an account with login: 'oona', password: 'monkey', password_confirmation: ''       and email: 'unactivated at example.com'
+    Then  she should be at the '<%= model_controller_routing_path %>/new' page
+     And  she should     see an errorExplanation message 'Password confirmation can't be blank'
+     And  no <%= file_name %> with login: 'oona' should exist
+     
+  Scenario: Anonymous <%= file_name %> can not create an account with mismatched password & password_confirmation
+    Given an anonymous <%= file_name %>
+     And  no <%= file_name %> with login: 'Oona' exists
+    When  she registers an account with login: 'oona', password: 'monkey', password_confirmation: 'monkeY' and email: 'unactivated at example.com'
+    Then  she should be at the '<%= model_controller_routing_path %>/new' page
+     And  she should     see an errorExplanation message 'Password doesn't match confirmation'
+     And  no <%= file_name %> with login: 'oona' should exist
+     
+  Scenario: Anonymous <%= file_name %> can not create an account with bad email
+    Given an anonymous <%= file_name %>
+     And  no <%= file_name %> with login: 'Oona' exists
+    When  she registers an account with login: 'oona', password: 'monkey', password_confirmation: 'monkey' and email: ''
+    Then  she should be at the '<%= model_controller_routing_path %>/new' page
+     And  she should     see an errorExplanation message 'Email can't be blank'
+     And  no <%= file_name %> with login: 'oona' should exist
+    When  she registers an account with login: 'oona', password: 'monkey', password_confirmation: 'monkey' and email: 'unactivated at example.com'
+    Then  she should be redirected to the home page
+    When  she follows that redirect!
+    Then  she should see a notice message 'Thanks for signing up!'
+     And  a <%= file_name %> with login: 'oona' should exist
+     And  the <%= file_name %> should have login: 'oona', and email: 'unactivated at example.com'
+<% if options[:include_activation] %>
+     And  the <%= file_name %>'s activation_code should not be nil
+     And  the <%= file_name %>'s activated_at    should     be nil
+     And  she should not be logged in
+<% else %>
+     And  oona should be logged in
+<% end %>
+     
+<% if options[:include_activation] %>
+Story: Activating an account
+  As a registered, but not yet activated, <%= file_name %>
+  I want to be able to activate my account
+  So that I can log in to the site
+
+  #
+  # Successful activation
+  #
+  Scenario: Not-yet-activated <%= file_name %> can activate her account
+    Given a registered <%= file_name %> named 'Reggie'
+     And  the <%= file_name %> has activation_code: 'activate_me', activated_at: nil! 
+     And  we try hard to remember the <%= file_name %>'s updated_at, and created_at
+    When  she goes to /activate/activate_me
+    Then  she should be redirected to 'login'
+    When  she follows that redirect!
+    Then  she should see a notice message 'Signup complete!'
+     And  a <%= file_name %> with login: 'reggie' should exist
+     And  the <%= file_name %> should have login: 'reggie', and email: 'registered at example.com'
+     And  the <%= file_name %>'s activation_code should     be nil
+     And  the <%= file_name %>'s activated_at    should not be nil
+     And  she should not be logged in
+
+  #
+  # Unsuccessful activation
+  #
+  Scenario: Not-yet-activated <%= file_name %> can't activate her account with a blank activation code
+    Given a registered <%= file_name %> named 'Reggie'
+     And  the <%= file_name %> has activation_code: 'activate_me', activated_at: nil! 
+     And  we try hard to remember the <%= file_name %>'s updated_at, and created_at
+    When  she goes to /activate/
+    Then  she should be redirected to the home page
+    When  she follows that redirect!
+    Then  she should see an error  message 'activation code was missing'
+     And  a <%= file_name %> with login: 'reggie' should exist
+     And  the <%= file_name %> should have login: 'reggie', activation_code: 'activate_me', and activated_at: nil!
+     And  the <%= file_name %>'s updated_at should stay the same under to_s
+     And  she should not be logged in
+  
+  Scenario: Not-yet-activated <%= file_name %> can't activate her account with a bogus activation code
+    Given a registered <%= file_name %> named 'Reggie'
+     And  the <%= file_name %> has activation_code: 'activate_me', activated_at: nil! 
+     And  we try hard to remember the <%= file_name %>'s updated_at, and created_at
+    When  she goes to /activate/i_haxxor_joo
+    Then  she should be redirected to the home page
+    When  she follows that redirect!
+    Then  she should see an error  message 'couldn\'t find a <%= file_name %> with that activation code'
+     And  a <%= file_name %> with login: 'reggie' should exist
+     And  the <%= file_name %> should have login: 'reggie', activation_code: 'activate_me', and activated_at: nil!
+     And  the <%= file_name %>'s updated_at should stay the same under to_s
+     And  she should not be logged in
+<% end %>

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/users/sessions.story
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/users/sessions.story	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/stories/users/sessions.story	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,134 @@
+Users want to know that nobody can masquerade as them.  We want to extend trust
+only to visitors who present the appropriate credentials.  Everyone wants this
+identity verification to be as secure and convenient as possible.
+
+Story: Logging in
+  As an anonymous <%= file_name %> with an account
+  I want to log in to my account
+  So that I can be myself
+
+  #
+  # Log in: get form
+  #
+  Scenario: Anonymous <%= file_name %> can get a login form.
+    Given an anonymous <%= file_name %>
+    When  she goes to /login
+    Then  she should be at the new <%= controller_file_name %> page
+     And  the page should look AWESOME
+     And  she should see a <form> containing a textfield: Login, password: Password, and submit: 'Log in'
+  
+  #
+  # Log in successfully, but don't remember me
+  #
+  Scenario: Anonymous <%= file_name %> can log in
+    Given an anonymous <%= file_name %>
+     And  an activated <%= file_name %> named 'reggie'
+    When  she creates a singular <%= controller_file_name %> with login: 'reggie', password: 'monkey', remember me: ''
+    Then  she should be redirected to the home page
+    When  she follows that redirect!
+    Then  she should see a notice message 'Logged in successfully'
+     And  reggie should be logged in
+     And  she should not have an auth_token cookie
+   
+  Scenario: Logged-in <%= file_name %> who logs in should be the new one
+    Given an activated <%= file_name %> named 'reggie'
+     And  an activated <%= file_name %> logged in as 'oona'
+    When  she creates a singular <%= controller_file_name %> with login: 'reggie', password: 'monkey', remember me: ''
+    Then  she should be redirected to the home page
+    When  she follows that redirect!
+    Then  she should see a notice message 'Logged in successfully'
+     And  reggie should be logged in
+     And  she should not have an auth_token cookie
+  
+  #
+  # Log in successfully, remember me
+  #
+  Scenario: Anonymous <%= file_name %> can log in and be remembered
+    Given an anonymous <%= file_name %>
+     And  an activated <%= file_name %> named 'reggie'
+    When  she creates a singular <%= controller_file_name %> with login: 'reggie', password: 'monkey', remember me: '1'
+    Then  she should be redirected to the home page
+    When  she follows that redirect!
+    Then  she should see a notice message 'Logged in successfully'
+     And  reggie should be logged in
+     And  she should have an auth_token cookie
+	      # assumes fixtures were run sometime
+     And  her session store should have <%= file_name %>_id: 4
+   
+  #
+  # Log in unsuccessfully
+  #
+  
+  Scenario: Logged-in <%= file_name %> who fails logs in should be logged out
+    Given an activated <%= file_name %> named 'oona'
+    When  she creates a singular <%= controller_file_name %> with login: 'oona', password: '1234oona', remember me: '1'
+    Then  she should be redirected to the home page
+    When  she follows that redirect!
+    Then  she should see a notice message 'Logged in successfully'
+     And  oona should be logged in
+     And  she should have an auth_token cookie
+    When  she creates a singular <%= controller_file_name %> with login: 'reggie', password: 'i_haxxor_joo'
+    Then  she should be at the new <%= controller_file_name %> page
+    Then  she should see an error message 'Couldn't log you in as 'reggie''
+     And  she should not be logged in
+     And  she should not have an auth_token cookie
+     And  her session store should not have <%= file_name %>_id
+  
+  Scenario: Log-in with bogus info should fail until it doesn't
+    Given an activated <%= file_name %> named 'reggie'
+    When  she creates a singular <%= controller_file_name %> with login: 'reggie', password: 'i_haxxor_joo'
+    Then  she should be at the new <%= controller_file_name %> page
+    Then  she should see an error message 'Couldn't log you in as 'reggie''
+     And  she should not be logged in
+     And  she should not have an auth_token cookie
+     And  her session store should not have <%= file_name %>_id
+    When  she creates a singular <%= controller_file_name %> with login: 'reggie', password: ''
+    Then  she should be at the new <%= controller_file_name %> page
+    Then  she should see an error message 'Couldn't log you in as 'reggie''
+     And  she should not be logged in
+     And  she should not have an auth_token cookie
+     And  her session store should not have <%= file_name %>_id
+    When  she creates a singular <%= controller_file_name %> with login: '', password: 'monkey'
+    Then  she should be at the new <%= controller_file_name %> page
+    Then  she should see an error message 'Couldn't log you in as '''
+     And  she should not be logged in
+     And  she should not have an auth_token cookie
+     And  her session store should not have <%= file_name %>_id
+    When  she creates a singular <%= controller_file_name %> with login: 'leonard_shelby', password: 'monkey'
+    Then  she should be at the new <%= controller_file_name %> page
+    Then  she should see an error message 'Couldn't log you in as 'leonard_shelby''
+     And  she should not be logged in
+     And  she should not have an auth_token cookie
+     And  her session store should not have <%= file_name %>_id
+    When  she creates a singular <%= controller_file_name %> with login: 'reggie', password: 'monkey', remember me: '1'
+    Then  she should be redirected to the home page
+    When  she follows that redirect!
+    Then  she should see a notice message 'Logged in successfully'
+     And  reggie should be logged in
+     And  she should have an auth_token cookie
+	      # assumes fixtures were run sometime
+     And  her session store should have <%= file_name %>_id: 4
+
+
+  #
+  # Log out successfully (should always succeed)
+  #
+  Scenario: Anonymous (logged out) <%= file_name %> can log out.
+    Given an anonymous <%= file_name %>
+    When  she goes to /logout
+    Then  she should be redirected to the home page
+    When  she follows that redirect!
+    Then  she should see a notice message 'You have been logged out'
+     And  she should not be logged in
+     And  she should not have an auth_token cookie
+     And  her session store should not have <%= file_name %>_id
+
+  Scenario: Logged in <%= file_name %> can log out.
+    Given an activated <%= file_name %> logged in as 'reggie'
+    When  she goes to /logout
+    Then  she should be redirected to the home page
+    When  she follows that redirect!
+    Then  she should see a notice message 'You have been logged out'
+     And  she should not be logged in
+     And  she should not have an auth_token cookie
+     And  her session store should not have <%= file_name %>_id

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/functional_test.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/functional_test.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/functional_test.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,88 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require '<%= controller_file_name %>_controller'
+
+# Re-raise errors caught by the controller.
+class <%= controller_class_name %>Controller; def rescue_action(e) raise e end; end
+
+class <%= controller_class_name %>ControllerTest < Test::Unit::TestCase
+  # Be sure to include AuthenticatedTestHelper in test/test_helper.rb instead
+  # Then, you can remove it from this and the units test.
+  include AuthenticatedTestHelper
+
+  fixtures :<%= table_name %>
+
+  def setup
+    @controller = <%= controller_class_name %>Controller.new
+    @request    = ActionController::TestRequest.new
+    @response   = ActionController::TestResponse.new
+  end
+
+  def test_should_login_and_redirect
+    post :create, :login => 'quentin', :password => 'monkey'
+    assert session[:<%= file_name %>_id]
+    assert_response :redirect
+  end
+
+  def test_should_fail_login_and_not_redirect
+    post :create, :login => 'quentin', :password => 'bad password'
+    assert_nil session[:<%= file_name %>_id]
+    assert_response :success
+  end
+
+  def test_should_logout
+    login_as :quentin
+    get :destroy
+    assert_nil session[:<%= file_name %>_id]
+    assert_response :redirect
+  end
+
+  def test_should_remember_me
+    @request.cookies["auth_token"] = nil
+    post :create, :login => 'quentin', :password => 'monkey', :remember_me => "1"
+    assert_not_nil @response.cookies["auth_token"]
+  end
+
+  def test_should_not_remember_me
+    @request.cookies["auth_token"] = nil
+    post :create, :login => 'quentin', :password => 'monkey', :remember_me => "0"
+    puts @response.cookies["auth_token"]
+    assert @response.cookies["auth_token"].blank?
+  end
+  
+  def test_should_delete_token_on_logout
+    login_as :quentin
+    get :destroy
+    assert @response.cookies["auth_token"].blank?
+  end
+
+  def test_should_login_with_cookie
+    <%= table_name %>(:quentin).remember_me
+    @request.cookies["auth_token"] = cookie_for(:quentin)
+    get :new
+    assert @controller.send(:logged_in?)
+  end
+
+  def test_should_fail_expired_cookie_login
+    <%= table_name %>(:quentin).remember_me
+    <%= table_name %>(:quentin).update_attribute :remember_token_expires_at, 5.minutes.ago
+    @request.cookies["auth_token"] = cookie_for(:quentin)
+    get :new
+    assert !@controller.send(:logged_in?)
+  end
+
+  def test_should_fail_cookie_login
+    <%= table_name %>(:quentin).remember_me
+    @request.cookies["auth_token"] = auth_token('invalid_auth_token')
+    get :new
+    assert !@controller.send(:logged_in?)
+  end
+
+  protected
+    def auth_token(token)
+      CGI::Cookie.new('name' => 'auth_token', 'value' => token)
+    end
+    
+    def cookie_for(<%= file_name %>)
+      auth_token <%= table_name %>(<%= file_name %>).remember_token
+    end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/mailer_test.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/mailer_test.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/mailer_test.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,31 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require '<%= file_name %>_mailer'
+
+class <%= class_name %>MailerTest < Test::Unit::TestCase
+  FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures'
+  CHARSET = "utf-8"
+
+  include ActionMailer::Quoting
+
+  def setup
+    ActionMailer::Base.delivery_method = :test
+    ActionMailer::Base.perform_deliveries = true
+    ActionMailer::Base.deliveries = []
+
+    @expected = TMail::Mail.new
+    @expected.set_content_type "text", "plain", { "charset" => CHARSET }
+  end
+
+  def test_dummy_test
+    #do nothing
+  end
+
+  private
+    def read_fixture(action)
+      IO.readlines("#{FIXTURES_PATH}/<%= file_name %>_mailer/#{action}")
+    end
+
+    def encode(subject)
+      quoted_printable(subject, CHARSET)
+    end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/model_functional_test.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/model_functional_test.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/model_functional_test.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,99 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require '<%= model_controller_file_name %>_controller'
+
+# Re-raise errors caught by the controller.
+class <%= model_controller_class_name %>Controller; def rescue_action(e) raise e end; end
+
+class <%= model_controller_class_name %>ControllerTest < Test::Unit::TestCase
+  # Be sure to include AuthenticatedTestHelper in test/test_helper.rb instead
+  # Then, you can remove it from this and the units test.
+  include AuthenticatedTestHelper
+
+  fixtures :<%= table_name %>
+
+  def setup
+    @controller = <%= model_controller_class_name %>Controller.new
+    @request    = ActionController::TestRequest.new
+    @response   = ActionController::TestResponse.new
+  end
+
+  def test_should_allow_signup
+    assert_difference '<%= class_name %>.count' do
+      create_<%= file_name %>
+      assert_response :redirect
+    end
+  end
+
+  def test_should_require_login_on_signup
+    assert_no_difference '<%= class_name %>.count' do
+      create_<%= file_name %>(:login => nil)
+      assert assigns(:<%= file_name %>).errors.on(:login)
+      assert_response :success
+    end
+  end
+
+  def test_should_require_password_on_signup
+    assert_no_difference '<%= class_name %>.count' do
+      create_<%= file_name %>(:password => nil)
+      assert assigns(:<%= file_name %>).errors.on(:password)
+      assert_response :success
+    end
+  end
+
+  def test_should_require_password_confirmation_on_signup
+    assert_no_difference '<%= class_name %>.count' do
+      create_<%= file_name %>(:password_confirmation => nil)
+      assert assigns(:<%= file_name %>).errors.on(:password_confirmation)
+      assert_response :success
+    end
+  end
+
+  def test_should_require_email_on_signup
+    assert_no_difference '<%= class_name %>.count' do
+      create_<%= file_name %>(:email => nil)
+      assert assigns(:<%= file_name %>).errors.on(:email)
+      assert_response :success
+    end
+  end
+  <% if options[:stateful] %>
+  def test_should_sign_up_user_in_pending_state
+    create_<%= file_name %>
+    assigns(:<%= file_name %>).reload
+    assert assigns(:<%= file_name %>).pending?
+  end<% end %>
+
+  <% if options[:include_activation] %>
+  def test_should_sign_up_user_with_activation_code
+    create_<%= file_name %>
+    assigns(:<%= file_name %>).reload
+    assert_not_nil assigns(:<%= file_name %>).activation_code
+  end
+
+  def test_should_activate_user
+    assert_nil <%= class_name %>.authenticate('aaron', 'test')
+    get :activate, :activation_code => <%= table_name %>(:aaron).activation_code
+    assert_redirected_to '/<%= controller_routing_path %>/new'
+    assert_not_nil flash[:notice]
+    assert_equal <%= table_name %>(:aaron), <%= class_name %>.authenticate('aaron', 'monkey')
+  end
+  
+  def test_should_not_activate_user_without_key
+    get :activate
+    assert_nil flash[:notice]
+  rescue ActionController::RoutingError
+    # in the event your routes deny this, we'll just bow out gracefully.
+  end
+
+  def test_should_not_activate_user_with_blank_key
+    get :activate, :activation_code => ''
+    assert_nil flash[:notice]
+  rescue ActionController::RoutingError
+    # well played, sir
+  end<% end %>
+
+  protected
+    def create_<%= file_name %>(options = {})
+      post :create, :<%= file_name %> => { :login => 'quire', :email => 'quire at example.com',
+        :password => 'quire69', :password_confirmation => 'quire69' }.merge(options)
+    end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/unit_test.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/unit_test.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/generators/authenticated/templates/test/unit_test.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,164 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class <%= class_name %>Test < Test::Unit::TestCase
+  # Be sure to include AuthenticatedTestHelper in test/test_helper.rb instead.
+  # Then, you can remove it from this and the functional test.
+  include AuthenticatedTestHelper
+  fixtures :<%= table_name %>
+
+  def test_should_create_<%= file_name %>
+    assert_difference '<%= class_name %>.count' do
+      <%= file_name %> = create_<%= file_name %>
+      assert !<%= file_name %>.new_record?, "#{<%= file_name %>.errors.full_messages.to_sentence}"
+    end
+  end
+<% if options[:include_activation] %>
+  def test_should_initialize_activation_code_upon_creation
+    <%= file_name %> = create_<%= file_name %>
+    <%= file_name %>.reload
+    assert_not_nil <%= file_name %>.activation_code
+  end
+<% end %><% if options[:stateful] %>
+  def test_should_create_and_start_in_pending_state
+    <%= file_name %> = create_<%= file_name %>
+    <%= file_name %>.reload
+    assert <%= file_name %>.pending?
+  end
+
+<% end %>
+  def test_should_require_login
+    assert_no_difference '<%= class_name %>.count' do
+      u = create_<%= file_name %>(:login => nil)
+      assert u.errors.on(:login)
+    end
+  end
+
+  def test_should_require_password
+    assert_no_difference '<%= class_name %>.count' do
+      u = create_<%= file_name %>(:password => nil)
+      assert u.errors.on(:password)
+    end
+  end
+
+  def test_should_require_password_confirmation
+    assert_no_difference '<%= class_name %>.count' do
+      u = create_<%= file_name %>(:password_confirmation => nil)
+      assert u.errors.on(:password_confirmation)
+    end
+  end
+
+  def test_should_require_email
+    assert_no_difference '<%= class_name %>.count' do
+      u = create_<%= file_name %>(:email => nil)
+      assert u.errors.on(:email)
+    end
+  end
+
+  def test_should_reset_password
+    <%= table_name %>(:quentin).update_attributes(:password => 'new password', :password_confirmation => 'new password')
+    assert_equal <%= table_name %>(:quentin), <%= class_name %>.authenticate('quentin', 'new password')
+  end
+
+  def test_should_not_rehash_password
+    <%= table_name %>(:quentin).update_attributes(:login => 'quentin2')
+    assert_equal <%= table_name %>(:quentin), <%= class_name %>.authenticate('quentin2', 'monkey')
+  end
+
+  def test_should_authenticate_<%= file_name %>
+    assert_equal <%= table_name %>(:quentin), <%= class_name %>.authenticate('quentin', 'monkey')
+  end
+
+  def test_should_set_remember_token
+    <%= table_name %>(:quentin).remember_me
+    assert_not_nil <%= table_name %>(:quentin).remember_token
+    assert_not_nil <%= table_name %>(:quentin).remember_token_expires_at
+  end
+
+  def test_should_unset_remember_token
+    <%= table_name %>(:quentin).remember_me
+    assert_not_nil <%= table_name %>(:quentin).remember_token
+    <%= table_name %>(:quentin).forget_me
+    assert_nil <%= table_name %>(:quentin).remember_token
+  end
+
+  def test_should_remember_me_for_one_week
+    before = 1.week.from_now.utc
+    <%= table_name %>(:quentin).remember_me_for 1.week
+    after = 1.week.from_now.utc
+    assert_not_nil <%= table_name %>(:quentin).remember_token
+    assert_not_nil <%= table_name %>(:quentin).remember_token_expires_at
+    assert <%= table_name %>(:quentin).remember_token_expires_at.between?(before, after)
+  end
+
+  def test_should_remember_me_until_one_week
+    time = 1.week.from_now.utc
+    <%= table_name %>(:quentin).remember_me_until time
+    assert_not_nil <%= table_name %>(:quentin).remember_token
+    assert_not_nil <%= table_name %>(:quentin).remember_token_expires_at
+    assert_equal <%= table_name %>(:quentin).remember_token_expires_at, time
+  end
+
+  def test_should_remember_me_default_two_weeks
+    before = 2.weeks.from_now.utc
+    <%= table_name %>(:quentin).remember_me
+    after = 2.weeks.from_now.utc
+    assert_not_nil <%= table_name %>(:quentin).remember_token
+    assert_not_nil <%= table_name %>(:quentin).remember_token_expires_at
+    assert <%= table_name %>(:quentin).remember_token_expires_at.between?(before, after)
+  end
+<% if options[:stateful] %>
+  def test_should_register_passive_<%= file_name %>
+    <%= file_name %> = create_<%= file_name %>(:password => nil, :password_confirmation => nil)
+    assert <%= file_name %>.passive?
+    <%= file_name %>.update_attributes(:password => 'new password', :password_confirmation => 'new password')
+    <%= file_name %>.register!
+    assert <%= file_name %>.pending?
+  end
+
+  def test_should_suspend_<%= file_name %>
+    <%= table_name %>(:quentin).suspend!
+    assert <%= table_name %>(:quentin).suspended?
+  end
+
+  def test_suspended_<%= file_name %>_should_not_authenticate
+    <%= table_name %>(:quentin).suspend!
+    assert_not_equal <%= table_name %>(:quentin), <%= class_name %>.authenticate('quentin', 'test')
+  end
+
+  def test_should_unsuspend_<%= file_name %>_to_active_state
+    <%= table_name %>(:quentin).suspend!
+    assert <%= table_name %>(:quentin).suspended?
+    <%= table_name %>(:quentin).unsuspend!
+    assert <%= table_name %>(:quentin).active?
+  end
+
+  def test_should_unsuspend_<%= file_name %>_with_nil_activation_code_and_activated_at_to_passive_state
+    <%= table_name %>(:quentin).suspend!
+    <%= class_name %>.update_all :activation_code => nil, :activated_at => nil
+    assert <%= table_name %>(:quentin).suspended?
+    <%= table_name %>(:quentin).reload.unsuspend!
+    assert <%= table_name %>(:quentin).passive?
+  end
+
+  def test_should_unsuspend_<%= file_name %>_with_activation_code_and_nil_activated_at_to_pending_state
+    <%= table_name %>(:quentin).suspend!
+    <%= class_name %>.update_all :activation_code => 'foo-bar', :activated_at => nil
+    assert <%= table_name %>(:quentin).suspended?
+    <%= table_name %>(:quentin).reload.unsuspend!
+    assert <%= table_name %>(:quentin).pending?
+  end
+
+  def test_should_delete_<%= file_name %>
+    assert_nil <%= table_name %>(:quentin).deleted_at
+    <%= table_name %>(:quentin).delete!
+    assert_not_nil <%= table_name %>(:quentin).deleted_at
+    assert <%= table_name %>(:quentin).deleted?
+  end
+<% end %>
+protected
+  def create_<%= file_name %>(options = {})
+    record = <%= class_name %>.new({ :login => 'quire', :email => 'quire at example.com', :password => 'quire69', :password_confirmation => 'quire69' }.merge(options))
+    record.<% if options[:stateful] %>register! if record.valid?<% else %>save<% end %>
+    record
+  end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/init.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/init.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/init.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,3 @@
+require File.dirname(__FILE__) + '/lib/authentication'
+require File.dirname(__FILE__) + '/lib/authentication/by_password'
+require File.dirname(__FILE__) + '/lib/authentication/by_cookie_token'

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/install.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/install.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/install.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1 @@
+puts IO.read(File.join(File.dirname(__FILE__), 'README'))
\ No newline at end of file

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authentication/by_cookie_token.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authentication/by_cookie_token.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authentication/by_cookie_token.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,85 @@
+# -*- coding: mule-utf-8 -*-
+module Authentication
+  module ByCookieToken
+    # Stuff directives into including module 
+    def self.included( recipient )
+      recipient.extend( ModelClassMethods )
+      recipient.class_eval do
+        include ModelInstanceMethods
+      end
+    end
+
+    #
+    # Class Methods
+    #
+    module ModelClassMethods      
+    end # class methods
+
+    #
+    # Instance Methods
+    #
+    module ModelInstanceMethods
+      def remember_token?
+        (!remember_token.blank?) && 
+          remember_token_expires_at && (Time.now.utc < remember_token_expires_at.utc)
+      end
+
+      # These create and unset the fields required for remembering users between browser closes
+      def remember_me
+        remember_me_for 2.weeks
+      end
+
+      def remember_me_for(time)
+        remember_me_until time.from_now.utc
+      end
+
+      def remember_me_until(time)
+        self.remember_token_expires_at = time
+        self.remember_token            = self.class.make_token
+        save(false)
+      end
+
+      # refresh token (keeping same expires_at) if it exists
+      def refresh_token
+        if remember_token?
+          self.remember_token = self.class.make_token 
+          save(false)      
+        end
+      end
+
+      # 
+      # Deletes the server-side record of the authentication token.  The
+      # client-side (browser cookie) and server-side (this remember_token) must
+      # always be deleted together.
+      #
+      def forget_me
+        self.remember_token_expires_at = nil
+        self.remember_token            = nil
+        save(false)
+      end
+    end # instance methods
+  end
+  
+
+  #
+  #
+  module ByCookieTokenController
+    # Stuff directives into including module 
+    def self.included( recipient )
+      recipient.extend( ControllerClassMethods )
+      recipient.class_eval do
+        include ControllerInstanceMethods
+      end
+    end
+
+    #
+    # Class Methods
+    #
+    module ControllerClassMethods
+    end # class methods
+    
+    module ControllerInstanceMethods
+    end # instance methods
+  end
+end
+

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authentication/by_password.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authentication/by_password.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authentication/by_password.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,65 @@
+module Authentication
+  module ByPassword
+    
+    # Stuff directives into including module
+    def self.included( recipient )
+      recipient.extend( ModelClassMethods )
+      recipient.class_eval do
+        include ModelInstanceMethods
+        
+        # Virtual attribute for the unencrypted password
+        attr_accessor :password
+        validates_presence_of     :password,                   :if => :password_required?
+        validates_presence_of     :password_confirmation,      :if => :password_required?
+        validates_confirmation_of :password,                   :if => :password_required?
+        validates_length_of       :password, :within => 6..40, :if => :password_required?
+        before_save :encrypt_password
+      end
+    end # #included directives
+
+    #
+    # Class Methods
+    #
+    module ModelClassMethods
+      # This provides a modest increased defense against a dictionary attack if
+      # your db were ever compromised, but will invalidate existing passwords.
+      # See the README and the file config/initializers/site_keys.rb
+      #
+      # It may not be obvious, but if you set REST_AUTH_SITE_KEY to nil and
+      # REST_AUTH_DIGEST_STRETCHES to 1 you'll have backwards compatibility with
+      # older versions of restful-authentication.
+      def password_digest(password, salt)
+        digest = REST_AUTH_SITE_KEY
+        REST_AUTH_DIGEST_STRETCHES.times do
+          digest = secure_digest(digest, salt, password, REST_AUTH_SITE_KEY)
+        end
+        digest
+      end      
+    end # class methods
+
+    #
+    # Instance Methods
+    #
+    module ModelInstanceMethods
+      
+      # Encrypts the password with the user salt
+      def encrypt(password)
+        self.class.password_digest(password, salt)
+      end
+      
+      def authenticated?(password)
+        crypted_password == encrypt(password)
+      end
+      
+      # before filter 
+      def encrypt_password
+        return if password.blank?
+        self.salt = self.class.make_token if new_record?
+        self.crypted_password = encrypt(password)
+      end
+      def password_required?
+        crypted_password.blank? || !password.blank?
+      end
+    end # instance methods
+  end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authentication.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authentication.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authentication.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,43 @@
+module Authentication
+  unless defined? CONSTANTS_DEFINED
+    # Uncomment to suit
+    RE_LOGIN_OK     = /\A\w[\w\.\-_@]+\z/                     # ASCII, strict
+    # RE_LOGIN_OK   = /\A[[:alnum:]][[:alnum:]\.\-_@]+\z/     # Unicode, strict
+    # RE_LOGIN_OK   = /\A[^[:cntrl:]\\<>\/&]*\z/              # Unicode, permissive
+    MSG_LOGIN_BAD   = "use only letters, numbers, and .-_@ please."
+
+    RE_NAME_OK      = /\A[^[:cntrl:]\\<>\/&]*\z/              # Unicode, permissive
+    MSG_NAME_BAD    = "avoid non-printing characters and \\&gt;&lt;&amp;/ please."
+
+    # This is purposefully imperfect -- it's just a check for bogus input. See
+    # http://www.regular-expressions.info/email.html
+    RE_EMAIL_NAME   = '[\w\.%\+\-]+'                          # what you actually see in practice
+    #RE_EMAIL_NAME   = '0-9A-Z!#\$%\&\'\*\+_/=\?^\-`\{|\}~\.' # technically allowed by RFC-2822
+    RE_DOMAIN_HEAD  = '(?:[A-Z0-9\-]+\.)+'
+    RE_DOMAIN_TLD   = '(?:[A-Z]{2}|com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum)'
+    RE_EMAIL_OK     = /\A#{RE_EMAIL_NAME}@#{RE_DOMAIN_HEAD}#{RE_DOMAIN_TLD}\z/i
+    MSG_EMAIL_BAD   = "should look like an email address."
+    
+    CONSTANTS_DEFINED = 'yup' # sorry for the C idiom
+  end
+  
+  def self.included( recipient )
+    recipient.extend( ModelClassMethods )
+    recipient.class_eval do
+      include ModelInstanceMethods
+    end
+  end
+
+  module ModelClassMethods
+    def secure_digest(*args)
+      Digest::SHA1.hexdigest(args.flatten.join('--'))
+    end
+    def make_token
+      secure_digest(Time.now, (1..10).map{ rand.to_s })
+    end 
+  end # class methods
+  
+  module ModelInstanceMethods
+  end # instance methods
+
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authorization/aasm_roles.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authorization/aasm_roles.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authorization/aasm_roles.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,64 @@
+module Authorization
+  module AasmRoles
+    unless Object.constants.include? "STATEFUL_ROLES_CONSTANTS_DEFINED"
+      STATEFUL_ROLES_CONSTANTS_DEFINED = 'yup' # sorry for the C idiom
+    end
+    
+    def self.included( recipient )
+      recipient.extend( StatefulRolesClassMethods )
+      recipient.class_eval do
+        include StatefulRolesInstanceMethods
+        include AASM
+        aasm_column :state
+        aasm_initial_state :initial => :pending
+        aasm_state :passive
+        aasm_state :pending, :enter => :make_activation_code
+        aasm_state :active,  :enter => :do_activate
+        aasm_state :suspended
+        aasm_state :deleted, :enter => :do_delete
+
+        aasm_event :register do
+          transitions :from => :passive, :to => :pending, :guard => Proc.new {|u| !(u.crypted_password.blank? && u.password.blank?) }
+        end
+        
+        aasm_event :activate do
+          transitions :from => :pending, :to => :active 
+        end
+        
+        aasm_event :suspend do
+          transitions :from => [:passive, :pending, :active], :to => :suspended
+        end
+        
+        aasm_event :delete do
+          transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
+        end
+
+        aasm_event :unsuspend do
+          transitions :from => :suspended, :to => :active,  :guard => Proc.new {|u| !u.activated_at.blank? }
+          transitions :from => :suspended, :to => :pending, :guard => Proc.new {|u| !u.activation_code.blank? }
+          transitions :from => :suspended, :to => :passive
+        end
+      end
+    end
+
+    module StatefulRolesClassMethods
+      
+    end # class methods
+
+    module StatefulRolesInstanceMethods
+      # Returns true if the user has just been activated.
+      def recently_activated?
+        @activated
+      end
+      def do_delete
+        self.deleted_at = Time.now.utc
+      end
+
+      def do_activate
+        @activated = true
+        self.activated_at = Time.now.utc
+        self.deleted_at = self.activation_code = nil
+      end
+    end # instance methods
+  end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authorization/stateful_roles.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authorization/stateful_roles.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authorization/stateful_roles.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,63 @@
+module Authorization
+  module StatefulRoles
+    unless Object.constants.include? "STATEFUL_ROLES_CONSTANTS_DEFINED"
+      STATEFUL_ROLES_CONSTANTS_DEFINED = 'yup' # sorry for the C idiom
+    end
+    
+    def self.included( recipient )
+      recipient.extend( StatefulRolesClassMethods )
+      recipient.class_eval do
+        include StatefulRolesInstanceMethods
+        
+        acts_as_state_machine :initial => :pending
+        state :passive
+        state :pending, :enter => :make_activation_code
+        state :active,  :enter => :do_activate
+        state :suspended
+        state :deleted, :enter => :do_delete
+
+        event :register do
+          transitions :from => :passive, :to => :pending, :guard => Proc.new {|u| !(u.crypted_password.blank? && u.password.blank?) }
+        end
+        
+        event :activate do
+          transitions :from => :pending, :to => :active 
+        end
+        
+        event :suspend do
+          transitions :from => [:passive, :pending, :active], :to => :suspended
+        end
+        
+        event :delete do
+          transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
+        end
+
+        event :unsuspend do
+          transitions :from => :suspended, :to => :active,  :guard => Proc.new {|u| !u.activated_at.blank? }
+          transitions :from => :suspended, :to => :pending, :guard => Proc.new {|u| !u.activation_code.blank? }
+          transitions :from => :suspended, :to => :passive
+        end
+      end
+    end
+
+    module StatefulRolesClassMethods
+      
+    end # class methods
+
+    module StatefulRolesInstanceMethods
+      # Returns true if the user has just been activated.
+      def recently_activated?
+        @activated
+      end
+      def do_delete
+        self.deleted_at = Time.now.utc
+      end
+
+      def do_activate
+        @activated = true
+        self.activated_at = Time.now.utc
+        self.deleted_at = self.activation_code = nil
+      end
+    end # instance methods
+  end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authorization.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authorization.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/authorization.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,15 @@
+module Authorization
+
+  def self.included( recipient )
+    recipient.extend( ModelClassMethods )
+    recipient.class_eval do
+      include ModelInstanceMethods
+    end
+  end
+
+  module ModelClassMethods
+  end # class methods
+
+  module ModelInstanceMethods
+  end # instance methods
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/trustification/email_validation.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/trustification/email_validation.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/trustification/email_validation.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,20 @@
+module Trustification
+  module EmailValidation
+    unless Object.constants.include? "CONSTANTS_DEFINED"
+      CONSTANTS_DEFINED = 'yup' # sorry for the C idiom
+    end
+    
+    def self.included( recipient )
+      recipient.extend( ClassMethods )
+      recipient.class_eval do
+        include InstanceMethods
+      end
+    end
+
+    module ClassMethods
+    end # class methods
+
+    module InstanceMethods
+    end # instance methods
+  end
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/trustification.rb
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/trustification.rb	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/lib/trustification.rb	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,15 @@
+module Trustification
+
+  def self.included( recipient )
+    recipient.extend( ModelClassMethods )
+    recipient.class_eval do
+      include ModelInstanceMethods
+    end
+  end
+
+  module ModelClassMethods
+  end # class methods
+
+  module ModelInstanceMethods
+  end # instance methods
+end

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/AccessControl.txt
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/AccessControl.txt	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/AccessControl.txt	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,2 @@
+
+See the notes in [[Authorization]]

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Authentication.txt
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Authentication.txt	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Authentication.txt	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,5 @@
+Guides to best practices:
+* "The OWASP Guide to Building Secure Web Applications":http://www.owasp.org/index.php/Category:OWASP_Guide_Project
+** specifically, of course, the chapter on Authentication.
+* "Secure Programming for Linux and Unix HOWTO":http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/web-authentication.html
+* "Authentication and Identification,":http://www.downes.ca/post/12 by Stephen Downes **Highly Recommended**

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Authorization.txt
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Authorization.txt	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Authorization.txt	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,154 @@
+h2. Authorization
+
+"Best Practices for Authorization":http://www.owasp.org/index.php/Guide_to_Authorization
+# auth system should deny by default
+# Principle of least privilege (fine-grain)
+# each non-anonymous entry point have an access control check
+# authorization check at or near the beginning of code implementing sensitive activities
+# Ensure that Model code checks to ensure that the requesting user should have access to the protected resource.
+# Reauthorization for high value activities or after idle out
+# If custom code is required to perform authorization functions, consider
+  fail-safe authentication and exception handling – ensure that if an exception
+  is thrown, the user is logged out or at least prevented from accessing the
+  protected resource or function.
+# Well written applications centralize access control routines, so if any bugs
+  are found, they can be fixed once and the results apply throughout the
+  application immediately.
+
+h2. Authorization in a trust context
+
+* [http://en.wikipedia.org/wiki/Authorization]
+* remember: goal is **prediction** not **control**
+
+h2. Patterns for Policy definition / Authorization / access control
+
+*Reference Monitor (SecPatt p256)
+** Set of authorization rules
+** Actor, Action, Resource => Monitor+(rules) => ctrlr
+* Role based:
+   subj, role, right. action, resource
+  RBAC, access is controlled at the system level, outside of the user's control
+* Filter based
+  User x Controller x Action x Params --
+* Object based
+  model security delegation
+* Access Control Matrix http://en.wikipedia.org/wiki/Access_Control_Matrix
+* CommandProcessor pattern (DSL approach)
+* DENY FROM ... / ALLOW FROM ... approach
+* Capability based control: bundle together the designation of an object and the permission to access that object
+  ie. I can name it if and only if I am allowed to get at it.
+
+h2. Notes from "Security patterns":http://www.amazon.com/Security-Patterns-Integrating-Engineering-Software/dp/0470858842
+by M Schumacher ("website for book":http://www.securitypatterns.org/)
+
+Reference Monitor (SecPatt p256)
+ * Set of authorization rules
+ * Actor, Action, Resource  => Monitor+(rules) => ctrlr
+
+= Full access with Errors (SecPatt p305)
+
+* Users should not be able to view data or perform operations for which they
+  have no permissions.
+* Hiding an available and accessible function is inappropriate, because users
+  must be able to see what they can do.
+* The visual appeal and usability of a graphical user interface (GUI) can be de-
+  graded by varying layouts depending on the (current) access rights of a
+  user. For example, blank space might appear for some users where others see
+  options they can access, or sequence and number of menu items might differ,
+  depending on the current user’s rights, and thus ‘blind’ operation of the menu
+  by an expe- rienced user is no longer possible.
+* Showing currently unavailable functions can tease users to into upgrading
+  their access rights, for example by paying for the access or buying a license
+  after us- ing a demo version.
+* Trial and error are ineffective means of learning which functions are
+  accessible.  Invoking an operation only to learn that it doesn’t work with
+  your access rights is confusing.
+* The privilege grouping of the typical user community might not be known at the
+  design time of the GUI, and it might change over time, for example through
+  organizational or business process changes, so that providing a few special
+  modes of the GUI depending on the corresponding user roles is inappropriate.
+* Checking whether a function is allowed by a user is most efficient, robust and
+  secure, if done by the function itself—at least the code performing the checks
+  is then closely related to the code performing the subsequent operation
+  afterwards.
+
+h2. Outcomes / Obligations
+
+-- forbid
+-- ask for trust escalation (eg log in, prove_as_human, validate_email, are_you_sure, send_me_ten_cents)
+-- drag ass
+-- permit
+
+-- reinterpret past actions based on future evolution of trust
+-- prioritize changesets based on trust.
+
+
+h2. Notes from "Core Security Patterns":http://www.coresecuritypatterns.com/patterns.htm website
+
+# Authentication Enforcer 	who the hell are you
+# Intercepting Validator	Is your request well-formed
+# Authorization Enforcer  	Are you allowed to do that
+# Secure Logger 		Know what's happening/happened
+#
+
+h2. notes from "XACML":http://www.nsitonline.in/hemant/stuff/xacml/XACML%20Tutorial%20with%20a%20Use%20Case%20Scenario%20for%20Academic%20Institutions.htm
+
+PolicySets [Policy Combining Algorithm]
+Policy [Rule Combining Algorithm] (defines access to particular resources.)
+# Target
+## Subject Attributes
+## Resource Attributes
+## Action Attributes
+## Environment Attributes
+# Rule [Effect]		Identify various conditions or cases under which a policy may become applicable
+## Subject Attributes	user who has made an access request
+## Resource Attributes	object to which access is requested
+## Action Attributes	action the subject wants to take on the resource
+## Environment Attributes	request environment (time of day, ip, etc)
+## Conditions
+# Obligations
+
+Roles    -- student, janitor, dean, stranger, ...
+Branches -- Departments, etc.
+
+* Examine applicable rules until you get an outcome, failure or passes thru (in which case rejected)
+* Rule combining Algorithms
+
+* Obligations -- things to do once requests have been denied or permitted
+
+Reference Monitor (SecPatt p256)
+ * Set of authorization rules
+ * Actor, Action, Resource  --> Monitor+(rules) --> ctrlr
+
+#
+# ask for permissions on arbitrary (subject, action, resource)
+  * roles
+# get filtered object based on action (:public_info, :admin_info, etc.)
+# attach a rule to a (subject|role, action, resource) triple
+  "subject should have role R"
+  "subject should have role R on resource X"
+  "should meet the
+
+* Role supervisor:
+  * adds, defines, removes roles.  no policy -- just attaches roles to users
+
+* Policy
+  answers "can Actor do Action to Resource"
+  * Rules
+  * Rule resolution
+  * outcome, obligations.
+  policy definitions can come from many places, go to policy mgr.
+* Hall monitor
+  enforces policy (before filters)
+* Policy observers
+  handle policy obligations
+
+* Athentication   --  identification, really: securely attach visitor to identity
+* Validation      -- qualify trust
+* Access control  -- define policy
+** Roles
+** Acc. matrix
+* Authorization	-- enforce policy (reference monitor ; filter chain)
+* Obligations
+**  Audit 	-- (observer)
+

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/RailsPlugins.txt
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/RailsPlugins.txt	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/RailsPlugins.txt	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,78 @@
+h1. Rails Authentication, Authorization and Access Control plugins
+
+h2. Authentication plugins
+
+* http://github.com/technoweenie/restful-authentication/tree/master -- the accepted standard for authentication
+* http://github.com/mrflip/restful-authentication/tree/master -- my fork of restful_authentication with more modularity, more specs and a few security tweaks
+* http://github.com/josh/open_id_authentication/tree/master -- OpenID authentication
+
+h2. Authorization plugins
+
+From
+* http://agilewebdevelopment.com/plugins/tag/security
+* http://www.vaporbase.com/postings/Authorization_in_Rails
+
+* http://github.com/jbarket/restful-authorization/tree/master
+
+* http://agilewebdevelopment.com/plugins/rolerequirement
+  http://code.google.com/p/rolerequirement/
+  http://rolerequirement.googlecode.com/svn/tags/role_requirement/
+  9 votes
+
+* http://github.com/ezmobius/acl_system2/
+  http://agilewebdevelopment.com/plugins/acl_system
+  http://opensvn.csie.org/ezra/rails/plugins/dev/acl_system2/
+  last touched 2006
+  57 votes on AWD
+  * also: http://agilewebdevelopment.com/plugins/acl_system2_ownership
+
+  bq. access_control [:new, :create, :update, :edit] => '(admin | user |
+                      moderator)', :delete => 'admin'
+      <% restrict_to "(admin | moderator) & !blacklist" do %>
+        <%= link_to "Admin & Moderator only link", :action =>'foo' %>
+      <% end %>
+
+* Authorization Recipe (from Rails Recipes #32)
+  http://www.vaporbase.com/postings/Authorization_in_Rails
+  http://opensvn.csie.org/mabs29/plugins/simple_access_control
+
+* Active ACL
+  http://phpgacl.sourceforge.net/demo/phpgacl/docs/manual.html
+  (Access-matrix driven)
+
+* http://github.com/aiwilliams/access_controlled_system
+
+* http://agilewebdevelopment.com/plugins/access
+
+* http://robzon.aenima.pl/2007/12/base-auth-is-out.html
+  http://agilewebdevelopment.com/plugins/base_auth
+  http://base-auth.googlecode.com/svn/trunk/
+  40 votes
+
+* http://agilewebdevelopment.com/plugins/authorization
+  http://www.writertopia.com/developers/authorization
+  http://github.com/DocSavage/rails-authorization-plugin/tree/master
+  Opaque policy descriptions
+  19 votes
+
+* http://github.com/shuber/access_control_list/
+  Not much there yet
+
+* https://opensvn.csie.org/traccgi/tobionrails
+  http://agilewebdevelopment.com/plugins/access_control
+  http://opensvn.csie.org/tobionrails/plugins/access_control
+  last touched 1 year ago
+
+* http://github.com/mdarby/restful_acl/
+  -- google code too --
+  Just does REST?  More of an app than a plugin.
+
+* http://github.com/stonean/lockdown/tree/master
+  http://lockdown.rubyforge.org
+  http://groups.google.com/group/stonean_lockdown?hl=en
+  "Lockdown stores an array of access rights in the session"
+
+h2. Trust / Validation etc. plugins
+
+
+* http://agilewebdevelopment.com/plugins/recaptcha

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/SecurityFramework.graffle
===================================================================
(Binary files differ)


Property changes on: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/SecurityFramework.graffle
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/SecurityFramework.png
===================================================================
(Binary files differ)


Property changes on: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/SecurityFramework.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/SecurityPatterns.txt
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/SecurityPatterns.txt	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/SecurityPatterns.txt	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,163 @@
+h1. Security from the perspective of a community site.
+
+Better than anything you'll read below on the subject:
+
+* "The OWASP Guide to Building Secure Web Applications":http://www.owasp.org/index.php/Category:OWASP_Guide_Project
+* "Secure Programming for Linux and Unix HOWTO":http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/web-authentication.html
+* "Core Security Patterns":http://www.coresecuritypatterns.com/patterns.htm
+* Stephen Downes' article on "Authentication and Identification":http://www.downes.ca/post/12
+
+h2. Snazzy Diagram
+
+!http://github.com/technoweenie/restful-authentication/tree/master/notes/SecurityFramework.png?raw=true!:http://github.com/technoweenie/restful-authentication/tree/master/notes/SecurityFramework.png
+
+(in notes/SecurityFramework.png)
+
+h2. Terms
+
+* Identification: Assign this visitor a name and an associated identity
+  (picture, website, favorite pokemon, trust metric, security roles).
+  
+  bq. "Behold. I am not Gandalf the Grey, whom you betrayed, I am Gandalf the White,
+  who has returned from death." -- Tolkien
+
+* Authentication: Verify this visitor matches the claimed identity.
+
+  bq. "My name is Werner Brandis. My voice is my password. Verify me." -- Sneakers
+
+* Authorization: Given a request (Actions+Resource+Environment), decide if it's safe.
+
+  bq. "Of every tree of the garden thou mayest freely eat: But of the tree of
+  the knowledge of good and evil, thou shalt not eat of it: for in the day that
+  thou eatest thereof thou shalt surely die." -- Gen 2:16-17
+  
+* Trust: Confidence this visitor will act reliably.
+  
+  bq. "A copper! A copper! How d'ya like that, boys? And we went for it. _I_ went
+  for it. Treated him like a kid brother. And I was gonna split fifty-fifty with
+  a copper." -- James Cagney, White Heat
+
+** Reputation from Trust Network: Award trust to this visitor based on what other trusted parties say.
+
+  bq. "He used my name? In the /street/?  He called me a punk? My name was on
+  the street? When we bounce from this s-t here, Y'all gonna go down on them
+  corners, let the people know: word did not get back to me. Let 'em know Marlo
+  step to any m-f-: Omar, Barksdale, whoever. My name IS my NAME." -- Marlo
+  Stansfield, The Wire (paraphrased)
+
+* Reputation from Past Actions:
+
+  bq. "The man you just killed was just released from prison. He could've f-in'
+  walked. All he had to do was say my dad's name, but he didn't; he kept his
+  f-ing mouth shut. And did his f-in' time, and he did it like a man. He did
+  four years for us.  So, Mr. Orange, you're tellin' me this very good friend of
+  mine, who did four years for my father, who in four years never made a deal,
+  no matter what they dangled in front of him, you're telling me that now, that
+  now this man is free, and we're making good on our commitment to him, he's
+  just gonna decide, out of the f-ing blue, to rip us off?" -- Nice Guy Eddie,
+  Reservoir Dogs
+
+* Access control
+  
+** Role
+  * http://en.wikipedia.org/wiki/Role-based_access_control
+  * "Role-Based Access Control FAQ":http://csrc.nist.gov/groups/SNS/rbac/faq.html
+  * "Role Based Access Control and Role Based Security":http://csrc.nist.gov/groups/SNS/rbac/ from the NIST Computer Security Division
+
+
+* Auditing & Recovery
+
+h2. Concept
+
+@  The below is a mixture of half-baked, foolish and incomplete. Just sos you know. @
+
+* Identity here will mean 'online presence' -- user account, basically.
+* Person will mean the remote endpoint -- whether that's a person or robot or
+  company.  (Security papers call this "Subject" but that's awful).
+* It's easy to confuse 'person' and 'identity', so easy I probably have below.
+
+Why do you need to authenticate?  For authorization. So traditionally, we think
+
+  person <- (ath'n token) <- identity <- (policy) <- actions
+
+That is, actions are attached to an identity by security policy, identity is
+attached to a person by their authentication token.
+
+The problem is that we cannot authenticate a /person/, only the token they
+present: password, ATM card+PIN number, etc.
+bq. "The Doors of Durin, Lord of Moria. Speak friend, and enter" -- Tolkien
+
+Anyone who presents that card+PIN, Elvish catchphrase, or voice print will be
+authenticated to act as the corresponding identity (account holder, friend of
+the elves, nerdy scientist), and we have no control over those tokens.
+
+  person <- (ath'n token) <- identity <- (az'n policy) <- actions
+        ^^^^ This step is wrong.
+
+The solution is to not care, or rather to reframe our goals.
+
+What we actually want is not to /control/ users' actions, but to /predict/ them.
+When Mr. Blonde helps Mr. White rob a jewelry store it's a security failure for
+the store but a success for the crime gang.  When Mr. Orange (an undercover cop)
+shoots Mr. Blonde it's a security failure for the crime gang and a success for
+the police.  We want to know how to use
+
+  ( identity, past actions ) => (trust, future actions)
+
+If you can predict someone is a vandal or troll, don't let them change pages, or
+only let them post to Ye Flaming Pitte of Flamage.
+
+We can to reasonable satisfaction authenticate a token: only grant that
+identity to visitors who bear that token.  So this part is fine:
+  
+    person   (token)<- identity
+
+But we have no control over authentication token - identity correspondence.
+This part is broken:
+
+    person x (token)<- identity
+
+The only one who does have that control is the person behind that identity.
+They can reasonably guarantee
+  
+    person ->(token)<- identity
+
+If that person is going to be in your community, they have an interest in their
+identity: they want to be known as someone who isn't a punk, or doesn't troll,
+or does troll and better than anyone, or won't rat you out to the cops.  The
+actions of a person are moderated by their interest in maintaining their
+reputation:
+  
+    past actions -> reputation ->person
+
+So give up authorization in favor of auditing and recoverability, and authorize
+based on reputation -- on the past behavior and vouchsafes offered by the
+identity,
+  
+    reputation -> trust -> permissions ->actions
+
+They want to know that they have full control of their identity; among other
+things, privacy and an understanding that nobody can act without permission on
+their behalf. In fact, we can assure that only a token-holder can assume the
+corresponding identity:
+  
+    person ->(token)<->identity ->(trust) actions ->reputation ->person
+
+poop
+
+    reputation ->trust
+
+
+So we need to
+* Understand and encourage how their security interests aligns with ours,
+* Understand how it doesn't, and be robust in the face of that; and
+* Recover gracefully if it goes wrong.
+
+Instead of
+
+  authorization -> user -> token -> identity
+  
+we assign roles based on
+
+  authorization <- trust <- reputation <- identity <- token <- person
+

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Tradeoffs.txt
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Tradeoffs.txt	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Tradeoffs.txt	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,126 @@
+Guides to best practices:
+* "The OWASP Guide to Building Secure Web Applications":http://www.owasp.org/index.php/Category:OWASP_Guide_Project
+* "Secure Programming for Linux and Unix HOWTO":http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/web-authentication.html
+* [[http://www.coresecuritypatterns.com/patterns.htm]]
+
+***************************************************************************
+h2. Session resetting
+
+Best practices recommend that you regenerate all session tokens (for us, the
+browser session ID and the remember_token cookie) on any privilege change (for
+us, logging in or logging out) -- see http://tinyurl.com/5vdvuq.  This release
+properly regenerates remember_token cookies, but does *not* by default
+reset_session.
+
+Calling reset_session can interact with Form Authentication tokens (a *much*
+more important security feature).  If a visitor logs in but has a form open in
+another tab, or uses the back button to pull one up from their history (perhaps
+the one that required them to log in), they will get the exceedingly unpleasant
+Request Forgery error.  Imagine spending twenty minutes crafting a devastating
+critique of this week's Battlestar Galactica episode, finding you need to log in
+before posting -- but then getting a Request Forgery when you re-attempt the
+post.  Frak!  Thus, it's disabled by defauly.
+
+On the other hand, this does moderately reduce your defense-in-depth against a
+"Cross-Site Request Forgery":http://en.wikipedia.org/wiki/CSRF attack.  To
+enable session_resetting, look for any
+   # reset session
+lines in the app/controllers/session_controller.rb and
+app/controllers/users_controller.rb and uncomment them.
+
+***************************************************************************
+h2. Site Key
+
+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.
+
+***************************************************************************
+h2. Password stretching
+
+If someone were to capture your user accounts database, they could farm it out
+for brute-force or dictionary-attack password cracking.  "Password Stretching"
+makes brute force (even with a compromised database and site key) attacks
+harder, and scales with Moore's law.  Basically, you apply the password
+encryption process several times, meaning that each brute-force attempt takes
+that much longer.  Hash your password ten times, and a brute-force attack takes
+ten times longer; hash 100,000 times and an attack takes 100,000 times longer.
+
+  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. ... Choose stretching factor so computing
+  K from (salt, passwd) takes 200-1000 ms. Store r with the user's password, and
+  increase it as computers get faster." -- http://tinyurl.com/37lb73
+  Practical Security (Ferguson & Scheier) p350
+
+Now, adding even a 0.2s delay to page requests isn't justifiable for most online
+applications, and storing r is unnecessary (at least on your first design
+iteration).  But 
+  On a 1G Slicehost already under moderate load:
+  irb(main):005:0> puts Time.now; (10**6).times{ secure_digest(Time.now, rand) }; puts Time.now
+  Fri May 16 08:26:16 +0000 2008
+  Fri May 16 08:30:58 +0000 2008
+  => 280s/1M ~= 0.000_3 ms / digest
+A modest 10 (the default here) foldings makes brute forcing, even given the site
+key and database, 10 times harder at a 3ms penalty.  An app that otherwise
+serves 100 reqs/s is reduced to 78 signin reqs/s; an app that does 10reqs/s is
+reduced to 9.7 signin reqs/s
+
+* http://www.owasp.org/index.php/Hashing_Java
+* "An Illustrated Guide to Cryptographic Hashes":http://www.unixwiz.net/techtips/iguide-crypto-hashes.html
+
+The default of 10 is a reasonable compromise, but the security-paranoid and
+resource-rich may consider increasing REST_AUTH_DIGEST_STRETCHES to match the
+one-second best-practices value, while those with existing userbases (whose
+passwords would otherwise no longer work) should leave the value at one.
+
+***************************************************************************
+h2. Token regeneration
+
+The session and the remember_token should both be expired and regenerated
+every time we cross the logged out / logged in barrier by either password
+or cookie.  ("To reduce the risk from session hijacking":http://www.owasp.org/index.php/Session_Management#Regeneration_of_Session_Tokens
+and brute force attacks, the HTTP server can seamlessly expire and
+regenerate tokens. This decreases the window of opportunity for a replay or
+brute force attack.)  It does mean we set the cookie more often.
+
+  http://www.owasp.org/index.php/Session_Management#Regeneration_of_Session_Tokens
+  http://palisade.plynt.com/issues/2004Jul/safe-auth-practices/
+
+
+***************************************************************************
+h2. Field validation
+
+We restrict login names to only contain the characters
+<nowiki>A-Za-z0-9.-_@</nowiki> This allows (most) email addresses and is safe
+for urls, database expressions (the at sign, technically reserved in a url, will
+survive in most browsers).  If you want to be more permissive:
+*  "URL-legal characters":http://www.blooberry.com/indexdot/html/topics/urlencoding.htm are <nowiki>-_.!~*'()</nowiki>
+*  "XML-legal characters":http://www.sklar.com/blog/archives/96-XML-vs.-Control-Characters.html are <nowiki>Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]</nowiki>
+*  "Email-address legal characters":http://tools.ietf.org/html/rfc2822#section-3.4.1 are <nowiki>0-9a-zA-Z!#\$%\&\'\*\+_/=\?^\-`\{|\}~\.</nowiki> but see "this discussion of what is sane"http://www.regular-expressions.info/email.html (as opposed to legal)
+
+We restrict email addresses to match only those actually seen in the wild,
+invalidating some that are technically allowed (characters such as % and ! that
+date back to UUCP days.  The line to allow all RFC-2822 emails is commented out,
+so feel free to enable it, or remove this validation.  See "this discussion of
+what is sane"http://www.regular-expressions.info/email.html as opposed to what
+is legal.  Also understand that this is just a cursory bogus-input check --
+there's no guarantee that this email matches an account or is even well-formed.
+
+If you change these validations you should change the RSpec tests as well.
+

Added: branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Trustification.txt
===================================================================
--- branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Trustification.txt	                        (rev 0)
+++ branches/gsoc08-mpwa/vendor/plugins/restful_authentication/notes/Trustification.txt	2008-07-15 04:48:51 UTC (rev 38302)
@@ -0,0 +1,49 @@
+See also
+* "Trustlet Wiki":http://www.trustlet.org/wiki
+
+Potential Ingredients for a trust metric
+
+h2. Reputation
+
+* Web of trust
+* Reputation systems
+** Akismet, Viking, etc.
+
+* prove_as_human Completing a 
+* validate_email
+
+  logged_in
+  akismet, etc.
+  session duration
+
+h2. Accountability
+
+Does the person tied to this identity stand to lose or gain anything based on this action?
+
+
+h2. Past history
+
+* past history
+** we can revisit past trust decisions based on revised trust estimates
+* recency of errors (reduce trust on an application exception)
+
+h2. Commitment
+
+* are_you_sure -- ask for con
+* willingness to pay a "hate task" (compute big hash) a la Zed Shaw
+* send_me_one_cent a micropayment
+** shows commitment
+** secondary validation from payment system
+** offsets rist
+
+h2. Identity Binding
+
+* Stale sessions
+  bq. "If your application allows users to be logged in for long periods of time
+  ensure that controls are in place to revalidate a user’s authorization to a
+  resource. For example, if Bob has the role of “Top Secret” at 1:00, and at
+  2:00 while he is logged in his role is reduced to Secret he should not be able
+  to access “Top Secret” data any more." -- http://www.owasp.org/index.php/Guide_to_Authorization
+
+* how I authenticated: for instance, 'logged in by cookie' << 'logged in by password'
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macports-changes/attachments/20080714/179df046/attachment-0001.html 


More information about the macports-changes mailing list