amrita2 1.9.6 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. data/README +112 -0
  2. data/init.rb +6 -0
  3. data/lib/amrita2/gettext.rb +116 -0
  4. data/lib/amrita2/macro.rb +153 -0
  5. data/lib/amrita2/rails_bridge.rb +172 -26
  6. data/lib/amrita2/template.rb +2634 -234
  7. data/lib/amrita2/testsupport.rb +171 -0
  8. data/lib/amrita2/version.rb +3 -3
  9. data/lib/amrita2.rb +1 -0
  10. data/sample/depot/app/controllers/admin_controller.rb +59 -0
  11. data/sample/depot/app/controllers/application.rb +20 -0
  12. data/sample/depot/app/controllers/info_controller.rb +19 -0
  13. data/sample/depot/app/controllers/login_controller.rb +85 -0
  14. data/sample/depot/app/controllers/store_controller.rb +68 -0
  15. data/sample/depot/app/helpers/admin_helper.rb +7 -0
  16. data/sample/depot/app/helpers/application_helper.rb +10 -0
  17. data/sample/depot/app/helpers/ar_form.rb +169 -0
  18. data/sample/depot/app/helpers/form_tag.rb +24 -0
  19. data/sample/depot/app/helpers/info_helper.rb +7 -0
  20. data/sample/depot/app/helpers/standard_form.rb +73 -0
  21. data/sample/depot/app/helpers/store_helper.rb +14 -0
  22. data/sample/depot/app/models/cart.rb +36 -0
  23. data/sample/depot/app/models/cart_item.rb +26 -0
  24. data/sample/depot/app/models/line_item.rb +34 -0
  25. data/sample/depot/app/models/order.rb +57 -0
  26. data/sample/depot/app/models/product.rb +41 -0
  27. data/sample/depot/app/models/user.rb +83 -0
  28. data/sample/depot/config/boot.rb +49 -0
  29. data/sample/depot/config/environment.rb +83 -0
  30. data/sample/depot/config/environments/development.rb +24 -0
  31. data/sample/depot/config/environments/production.rb +24 -0
  32. data/sample/depot/config/environments/test.rb +24 -0
  33. data/sample/depot/config/routes.rb +10 -0
  34. data/sample/depot/db/migrate/001_create_products.rb +18 -0
  35. data/sample/depot/db/migrate/002_add_price.rb +14 -0
  36. data/sample/depot/db/migrate/003_add_test_data.rb +68 -0
  37. data/sample/depot/db/migrate/004_add_sessions.rb +20 -0
  38. data/sample/depot/db/migrate/005_create_orders.rb +21 -0
  39. data/sample/depot/db/migrate/006_create_line_items.rb +27 -0
  40. data/sample/depot/db/migrate/007_create_users.rb +18 -0
  41. data/sample/depot/db/schema.rb +45 -0
  42. data/sample/depot/public/dispatch.rb +15 -0
  43. data/sample/depot/test/functional/admin_controller_test.rb +54 -0
  44. data/sample/depot/test/functional/info_controller_test.rb +23 -0
  45. data/sample/depot/test/functional/login_controller_test.rb +74 -0
  46. data/sample/depot/test/functional/store_controller_test.rb +57 -0
  47. data/sample/depot/test/integration/dsl_user_stories_test.rb +126 -0
  48. data/sample/depot/test/integration/user_stories_test.rb +70 -0
  49. data/sample/depot/test/performance/order_speed_test.rb +58 -0
  50. data/sample/depot/test/test_helper.rb +16 -0
  51. data/sample/depot/test/unit/cart_test.rb +39 -0
  52. data/sample/depot/test/unit/cart_test1.rb +31 -0
  53. data/sample/depot/test/unit/line_item_test.rb +15 -0
  54. data/sample/depot/test/unit/order_test.rb +15 -0
  55. data/sample/depot/test/unit/product_test.rb +98 -0
  56. data/sample/depot/vendor/plugins/amrita2/init.rb +6 -0
  57. data/sample/hello/hello.rb +22 -0
  58. data/sample/login_engine/app/controllers/application.rb +16 -0
  59. data/sample/login_engine/app/controllers/user_controller.rb +265 -0
  60. data/sample/login_engine/app/helpers/application_helper.rb +3 -0
  61. data/sample/login_engine/app/helpers/form_tag.rb +16 -0
  62. data/sample/login_engine/app/helpers/two_columns.rb +24 -0
  63. data/sample/login_engine/app/helpers/two_columns_form.rb +47 -0
  64. data/sample/login_engine/app/helpers/user_helper.rb +88 -0
  65. data/sample/login_engine/app/models/user.rb +7 -0
  66. data/sample/login_engine/app/models/user_notify.rb +75 -0
  67. data/sample/login_engine/config/boot.rb +45 -0
  68. data/sample/login_engine/config/environment.rb +140 -0
  69. data/sample/login_engine/config/environments/development.rb +21 -0
  70. data/sample/login_engine/config/environments/production.rb +18 -0
  71. data/sample/login_engine/config/environments/test.rb +19 -0
  72. data/sample/login_engine/config/routes.rb +23 -0
  73. data/sample/login_engine/db/migrate/001_create_users.rb +25 -0
  74. data/sample/login_engine/db/schema.rb +25 -0
  75. data/sample/login_engine/lib/config.rb +113 -0
  76. data/sample/login_engine/lib/hpricot_test_extension.rb +80 -0
  77. data/sample/login_engine/lib/login_engine/authenticated_system.rb +113 -0
  78. data/sample/login_engine/lib/login_engine/authenticated_user.rb +155 -0
  79. data/sample/login_engine/lib/login_engine.rb +62 -0
  80. data/sample/login_engine/public/dispatch.rb +10 -0
  81. data/sample/login_engine/test/functional/amrita2_test.rb +267 -0
  82. data/sample/login_engine/test/functional/user_controller_test.rb +544 -0
  83. data/sample/login_engine/test/mocks/mail.rb +14 -0
  84. data/sample/login_engine/test/mocks/time.rb +19 -0
  85. data/sample/login_engine/test/test_helper.rb +31 -0
  86. data/sample/login_engine/test/unit/user_test.rb +116 -0
  87. data/sample/login_engine/vendor/plugins/amrita2/init.rb +6 -0
  88. data/specs/attribute.rb +201 -0
  89. data/specs/datatypes.rb +231 -0
  90. data/specs/dictionary.rb +68 -0
  91. data/specs/erb_cdata.rb +187 -0
  92. data/specs/filters.rb +513 -0
  93. data/specs/gettext/erb_gettext.rb +42 -0
  94. data/specs/gettext/gettext_util.rb +65 -0
  95. data/specs/gettext/static_text.rb +103 -0
  96. data/specs/impl/code_generator.rb +87 -0
  97. data/specs/impl/dynamic_element.rb +92 -0
  98. data/specs/impl/hash_delegator.rb +57 -0
  99. data/specs/impl/parse_opt.rb +34 -0
  100. data/specs/impl/preprocess.rb +823 -0
  101. data/specs/impl/testsupport.rb +89 -0
  102. data/specs/inlineruby.rb +429 -0
  103. data/specs/intro.rb +654 -0
  104. data/specs/loop.rb +203 -0
  105. data/specs/macro.rb +532 -0
  106. data/specs/sample.rb +34 -0
  107. data/specs/sanitize.rb +110 -0
  108. data/specs/template.rb +189 -0
  109. data/specs/trace.rb +97 -0
  110. metadata +138 -19
  111. data/lib/amrita2/core.rb +0 -1897
  112. data/lib/amrita2/rd.rb +0 -314
@@ -0,0 +1,113 @@
1
+ module LoginEngine
2
+ module AuthenticatedSystem
3
+
4
+ protected
5
+
6
+ # overwrite this if you want to restrict access to only a few actions
7
+ # or if you want to check if the user has the correct rights
8
+ # example:
9
+ #
10
+ # # only allow nonbobs
11
+ # def authorize?(user)
12
+ # user.login != "bob"
13
+ # end
14
+ def authorize?(user)
15
+ true
16
+ end
17
+
18
+ # overwrite this method if you only want to protect certain actions of the controller
19
+ # example:
20
+ #
21
+ # # don't protect the login and the about method
22
+ # def protect?(action)
23
+ # if ['action', 'about'].include?(action)
24
+ # return false
25
+ # else
26
+ # return true
27
+ # end
28
+ # end
29
+ def protect?(action)
30
+ true
31
+ end
32
+
33
+ # login_required filter. add
34
+ #
35
+ # before_filter :login_required
36
+ #
37
+ # if the controller should be under any rights management.
38
+ # for finer access control you can overwrite
39
+ #
40
+ # def authorize?(user)
41
+ #
42
+ def login_required
43
+ if not protect?(action_name)
44
+ return true
45
+ end
46
+
47
+ if user? and authorize?(session[:user])
48
+ return true
49
+ end
50
+
51
+ # store current location so that we can
52
+ # come back after the user logged in
53
+ store_location
54
+
55
+ # call overwriteable reaction to unauthorized access
56
+ access_denied
57
+ end
58
+
59
+ # overwrite if you want to have special behavior in case the user is not authorized
60
+ # to access the current operation.
61
+ # the default action is to redirect to the login screen
62
+ # example use :
63
+ # a popup window might just close itself for instance
64
+ def access_denied
65
+ redirect_to :controller => "/user", :action => "login"
66
+ end
67
+
68
+ # store current uri in the session.
69
+ # we can return to this location by calling return_location
70
+ def store_location
71
+ session['return-to'] = request.request_uri
72
+ end
73
+
74
+ # move to the last store_location call or to the passed default one
75
+ def redirect_to_stored_or_default(default=nil)
76
+ if session['return-to'].nil?
77
+ redirect_to default
78
+ else
79
+ redirect_to_url session['return-to']
80
+ session['return-to'] = nil
81
+ end
82
+ end
83
+
84
+ def redirect_back_or_default(default=nil)
85
+ if request.env["HTTP_REFERER"].nil?
86
+ redirect_to default
87
+ else
88
+ redirect_to(request.env["HTTP_REFERER"]) # same as redirect_to :back
89
+ end
90
+ end
91
+
92
+ def user?
93
+ # First, is the user already authenticated?
94
+ return true if not session[:user].nil?
95
+
96
+ # If not, is the user being authenticated by a token?
97
+ id = params[:user_id]
98
+ key = params[:key]
99
+ if id and key
100
+ session[:user] = User.authenticate_by_token(id, key)
101
+ return true if not session[:user].nil?
102
+ end
103
+
104
+ # Everything failed
105
+ return false
106
+ end
107
+
108
+ # Returns the current user from the session, if any exists
109
+ def current_user
110
+ session[:user]
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,155 @@
1
+ require 'digest/sha1'
2
+
3
+ # this model expects a certain database layout and its based on the name/login pattern.
4
+
5
+ module LoginEngine
6
+ module AuthenticatedUser
7
+
8
+ def self.included(base)
9
+ base.class_eval do
10
+
11
+ # use the table name given
12
+ set_table_name LoginEngine.config(:user_table)
13
+
14
+ attr_accessor :new_password
15
+
16
+ validates_presence_of :login
17
+ validates_length_of :login, :within => 3..40
18
+ validates_uniqueness_of :login
19
+ validates_uniqueness_of :email
20
+ validates_format_of :email, :with => /^[^@]+@.+$/
21
+
22
+ validates_presence_of :password, :if => :validate_password?
23
+ validates_confirmation_of :password, :if => :validate_password?
24
+ validates_length_of :password, { :minimum => 5, :if => :validate_password? }
25
+ validates_length_of :password, { :maximum => 40, :if => :validate_password? }
26
+
27
+ protected
28
+
29
+ attr_accessor :password, :password_confirmation
30
+
31
+ after_save :falsify_new_password
32
+ after_validation :crypt_password
33
+
34
+ end
35
+ base.extend(ClassMethods)
36
+ end
37
+
38
+ module ClassMethods
39
+
40
+ def authenticate(login, pass)
41
+ u = find(:first, :conditions => ["login = ? AND verified = 1 AND deleted = 0", login])
42
+ return nil if u.nil?
43
+ find(:first, :conditions => ["login = ? AND salted_password = ? AND verified = 1", login, AuthenticatedUser.salted_password(u.salt, AuthenticatedUser.hashed(pass))])
44
+ end
45
+
46
+ def authenticate_by_token(id, token)
47
+ # Allow logins for deleted accounts, but only via this method (and
48
+ # not the regular authenticate call)
49
+ u = find(:first, :conditions => ["#{User.primary_key} = ? AND security_token = ?", id, token])
50
+ return nil if u.nil? or u.token_expired?
51
+ return nil if false == u.update_expiry
52
+ u
53
+ end
54
+
55
+ end
56
+
57
+
58
+ protected
59
+
60
+ def self.hashed(str)
61
+ # check if a salt has been set...
62
+ if LoginEngine.config(:salt) == nil
63
+ raise "You must define a :salt value in the configuration for the LoginEngine module."
64
+ end
65
+
66
+ return Digest::SHA1.hexdigest("#{LoginEngine.config(:salt)}--#{str}--}")[0..39]
67
+ end
68
+
69
+ def self.salted_password(salt, hashed_password)
70
+ hashed(salt + hashed_password)
71
+ end
72
+
73
+ public
74
+
75
+ # hmmm, how does this interact with the developer's own User model initialize?
76
+ # We would have to *insist* that the User.initialize method called 'super'
77
+ #
78
+ def initialize(attributes = nil)
79
+ super
80
+ @new_password = false
81
+ end
82
+
83
+ def token_expired?
84
+ self.security_token and self.token_expiry and (Time.now > self.token_expiry)
85
+ end
86
+
87
+ def update_expiry
88
+ write_attribute('token_expiry', [self.token_expiry, Time.at(Time.now.to_i + 600 * 1000)].min)
89
+ write_attribute('authenticated_by_token', true)
90
+ write_attribute("verified", 1)
91
+ update_without_callbacks
92
+ end
93
+
94
+ def generate_security_token(hours = nil)
95
+ if not hours.nil? or self.security_token.nil? or self.token_expiry.nil? or
96
+ (Time.now.to_i + token_lifetime / 2) >= self.token_expiry.to_i
97
+ return new_security_token(hours)
98
+ else
99
+ return self.security_token
100
+ end
101
+ end
102
+
103
+ def set_delete_after
104
+ hours = LoginEngine.config(:delayed_delete_days) * 24
105
+ write_attribute('deleted', 1)
106
+ write_attribute('delete_after', Time.at(Time.now.to_i + hours * 60 * 60))
107
+
108
+ # Generate and return a token here, so that it expires at
109
+ # the same time that the account deletion takes effect.
110
+ return generate_security_token(hours)
111
+ end
112
+
113
+ def change_password(pass, confirm = nil)
114
+ self.password = pass
115
+ self.password_confirmation = confirm.nil? ? pass : confirm
116
+ @new_password = true
117
+ end
118
+
119
+ protected
120
+
121
+ def validate_password?
122
+ @new_password
123
+ end
124
+
125
+
126
+ def crypt_password
127
+ if @new_password
128
+ write_attribute("salt", AuthenticatedUser.hashed("salt-#{Time.now}"))
129
+ write_attribute("salted_password", AuthenticatedUser.salted_password(salt, AuthenticatedUser.hashed(@password)))
130
+ end
131
+ end
132
+
133
+ def falsify_new_password
134
+ @new_password = false
135
+ true
136
+ end
137
+
138
+ def new_security_token(hours = nil)
139
+ write_attribute('security_token', AuthenticatedUser.hashed(self.salted_password + Time.now.to_i.to_s + rand.to_s))
140
+ write_attribute('token_expiry', Time.at(Time.now.to_i + token_lifetime(hours)))
141
+ update_without_callbacks
142
+ return self.security_token
143
+ end
144
+
145
+ def token_lifetime(hours = nil)
146
+ if hours.nil?
147
+ LoginEngine.config(:security_token_life_hours) * 60 * 60
148
+ else
149
+ hours * 60 * 60
150
+ end
151
+ end
152
+
153
+ end
154
+ end
155
+
@@ -0,0 +1,62 @@
1
+ require 'login_engine/authenticated_user'
2
+ require 'login_engine/authenticated_system'
3
+
4
+ module LoginEngine
5
+ include AuthenticatedSystem # re-include the helper module
6
+
7
+ #--
8
+ # Define the configuration values. config sets the value of the
9
+ # constant ONLY if it has not already been set, i.e. by the user in
10
+ # environment.rb
11
+ #++
12
+
13
+ # Source address for user emails
14
+ config :email_from, 'webmaster@your.company'
15
+
16
+ # Destination email for system errors
17
+ config :admin_email, 'webmaster@your.company'
18
+
19
+ # Sent in emails to users
20
+ config :app_url, 'http://localhost:3000/'
21
+
22
+ # Sent in emails to users
23
+ config :app_name, 'TestApp'
24
+
25
+ # Email charset
26
+ config :mail_charset, 'utf-8'
27
+
28
+ # Security token lifetime in hours
29
+ config :security_token_life_hours, 24
30
+
31
+ # Two column form input
32
+ config :two_column_input, true
33
+
34
+ # Add all changeable user fields to this array.
35
+ # They will then be able to be edited from the edit action. You
36
+ # should NOT include the email field in this array.
37
+ config :changeable_fields, [ 'firstname', 'lastname' ]
38
+
39
+ # Set to true to allow delayed deletes (i.e., delete of record
40
+ # doesn't happen immediately after user selects delete account,
41
+ # but rather after some expiration of time to allow this action
42
+ # to be reverted).
43
+ config :delayed_delete, false
44
+
45
+ # Default is one week
46
+ config :delayed_delete_days, 7
47
+
48
+ # the table to store user information in
49
+ if ActiveRecord::Base.pluralize_table_names
50
+ config :user_table, "users"
51
+ else
52
+ config :user_table, "user"
53
+ end
54
+
55
+ # controls whether or not email is used
56
+ config :use_email_notification, true
57
+
58
+ # Controls whether accounts must be confirmed after signing up
59
+ # ONLY if this and use_email_notification are both true
60
+ config :confirm_account, true
61
+
62
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
4
+
5
+ # If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
6
+ # "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
7
+ require "dispatcher"
8
+
9
+ ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
10
+ Dispatcher.dispatch
@@ -0,0 +1,267 @@
1
+
2
+ require File.dirname(__FILE__) + '/../test_helper'
3
+ require 'user_controller'
4
+ require 'amrita2/testsupport'
5
+
6
+
7
+ # Re-raise errors caught by the controller.
8
+ class UserController; def rescue_action(e) raise e end; end
9
+
10
+ class UserControllerTestWithAmrita2 < Test::Unit::TestCase
11
+ include Amrita2::TestSupport
12
+ fixtures :users
13
+
14
+ def setup
15
+ LoginEngine::CONFIG[:salt] = "test-salt"
16
+
17
+ @controller = UserController.new
18
+ @request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
19
+ @request.host = "localhost"
20
+ end
21
+
22
+ def test_invalid_login
23
+ post :login, :user => { :login => "bob", :password => "wrong_password" }
24
+ assert_response :success
25
+
26
+ assert_nil session[:user]
27
+ assert_template "login"
28
+ #puts @response.body
29
+ assert_equal_as_xml @response.body, <<EOF
30
+ <html>
31
+ <head>
32
+ <title>MyApp</title>
33
+ <link href='/stylesheets/login_engine.css' media='screen' rel='Stylesheet' type='text/css' />
34
+ </head>
35
+ <body>
36
+ <div id='warning'>Login unsuccessful</div>
37
+ <div title="UserController login" class="form">
38
+ <h3>Please Login</h3>
39
+ <div class="form-padding">
40
+ <form action="/user/login" method="post">
41
+ <table>
42
+ <tr class="two_columns">
43
+ <td class="prompt"><label>Login ID:</label></td>
44
+ <td class="value"><input id="user_login" name="user[login]" size="30" type="text" value="bob"/></td>
45
+ </tr>
46
+ <tr class="two_columns">
47
+ <td class="prompt"><label>Password:</label></td>
48
+ <td class="value"><input id="user_password" name="user[password]" size="30" type="password" value=""/></td>
49
+ </tr>
50
+ </table>
51
+ <div class="button-bar">
52
+ <input name="commit" type="submit" value="Login" />
53
+ <a href="/user/signup">Register for an account</a> |
54
+ <a href="/user/forgot_password">Forgot my password</a>
55
+ </div>
56
+ </form>
57
+ </div>
58
+ </div>
59
+ </body>
60
+ </html>
61
+ EOF
62
+ end
63
+
64
+ def test_invalid_login_ja
65
+ post :login, :user => { :login => "bob", :password => "wrong_password" }, :lang=>'ja'
66
+ assert_response :success
67
+
68
+ assert_nil session[:user]
69
+ assert_template "login"
70
+ assert_equal_as_xml @response.body, <<EOF
71
+ <html>
72
+ <head>
73
+ <title>MyApp</title>
74
+ <link href='/stylesheets/login_engine.css' media='screen' rel='Stylesheet' type='text/css' />
75
+ </head>
76
+ <body>
77
+ <div id='warning'>ログイン失敗</div>
78
+ <div title="UserController login" class="form">
79
+ <h3>ログインしてください</h3>
80
+ <div class="form-padding">
81
+ <form action="/user/login" method="post">
82
+ <table>
83
+ <tr class="two_columns">
84
+ <td class="prompt"><label>ログインID</label></td>
85
+ <td class="value"><input id="user_login" name="user[login]" size="30" type="text" value="bob"/></td>
86
+ </tr>
87
+ <tr class="two_columns">
88
+ <td class="prompt"><label>パスワード</label></td>
89
+ <td class="value"><input id="user_password" name="user[password]" size="30" type="password" value=""/></td>
90
+ </tr>
91
+ </table>
92
+ <div class="button-bar">
93
+ <input name="commit" type="submit" value="ログイン" />
94
+ <a href="/user/signup">新規登録する</a> |
95
+ <a href="/user/forgot_password">パスワードを忘れた時はこちら</a>
96
+ </div>
97
+ </form>
98
+ </div>
99
+ </div>
100
+ </body>
101
+ </html>
102
+ EOF
103
+ end
104
+
105
+ def test_signup_bad_password
106
+ LoginEngine::CONFIG[:use_email_notification] = true
107
+ ActionMailer::Base.deliveries = []
108
+
109
+ @request.session['return-to'] = "/bogus/location"
110
+ post :signup, :user => { :login => "newbob", :password => "bad", :password_confirmation => "bad", :email => "newbob@test.com" }
111
+ assert_nil session[:user]
112
+ #assert_invalid_column_on_record "user", "password"
113
+ assert assigns["user"].errors.invalid?("password")
114
+
115
+ assert_response :success
116
+ assert_equal 0, ActionMailer::Base.deliveries.size
117
+
118
+ #puts @response.body
119
+ assert_equal_as_xml @response.body, <<EOF
120
+ <html>
121
+ <head>
122
+ <title>MyApp</title>
123
+ <link href='/stylesheets/login_engine.css' media='screen' rel='Stylesheet' type='text/css' />
124
+ </head>
125
+ <body>
126
+
127
+ <div title="UserController signup" class="form">
128
+ <h3>Signup</h3>
129
+
130
+ <div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this user from being saved</h2><p>There was a problem with the following field:</p><ul><li>Password is too short (minimum is 5 characters)</li></ul></div>
131
+
132
+ <div class="form-padding">
133
+ <form action="/user/signup" method="post">
134
+ <div class="user_edit">
135
+ <table>
136
+ <tr class="two_columns">
137
+ <td class="prompt"><label>First Name:</label></td>
138
+ <td class="value"><input id="user_firstname" name="user[firstname]" size="30" type="text" /></td>
139
+ </tr>
140
+
141
+ <tr class="two_columns">
142
+ <td class="prompt"><label>Last Name:</label></td>
143
+ <td class="value"><input id="user_lastname" name="user[lastname]" size="30" type="text" /></td>
144
+ </tr>
145
+
146
+ <tr class="two_columns">
147
+ <td class="prompt"><label>Login ID:</label></td>
148
+ <td class="value"><input id="user_login" name="user[login]" size="30" type="text" value="newbob" /></td>
149
+ </tr>
150
+ <tr class="two_columns">
151
+ <td class="prompt"><label>Email:</label></td>
152
+ <td class="value"><input id="user_email" name="user[email]" size="30" type="text" value="newbob@test.com" /></td>
153
+ </tr>
154
+
155
+
156
+ </table>
157
+ </div>
158
+ <br/>
159
+ <div class="user_password">
160
+ <table>
161
+ <tr class="two_columns">
162
+ <td class="prompt"><label>Password:</label></td>
163
+ <td class="value"><div class="fieldWithErrors"><input id="user_password" name="user[password]" size="30" type="password" value="" /></div></td>
164
+ </tr>
165
+
166
+ <tr class="two_columns">
167
+ <td class="prompt"><label>Password Confirmation:</label></td>
168
+ <td class="value"><input id="user_password_confirmation" name="user[password_confirmation]" size="30" type="password" value="" /></td>
169
+ </tr>
170
+
171
+
172
+ </table>
173
+ </div>
174
+
175
+ <div class="button-bar">
176
+ <input name="commit" type="submit" value="Signup" />
177
+ <a href="/user/login">Cancel</a>
178
+ </div>
179
+ </form>
180
+ </div>
181
+ </div>
182
+ </body>
183
+ </html>
184
+ EOF
185
+ end
186
+
187
+ def test_edit
188
+ post :login, :user => { :login => "bob", :password => "atest" }
189
+ assert(@response.has_session_object?(:user))
190
+
191
+ get :edit
192
+ assert_response :success
193
+
194
+ #puts @response.body
195
+ assert_equal_as_xml @response.body, <<EOF
196
+
197
+ <html>
198
+ <head>
199
+ <title>MyApp</title>
200
+ <link href='/stylesheets/login_engine.css' media='screen' rel='Stylesheet' type='text/css' />
201
+ </head>
202
+ <body>
203
+
204
+
205
+ <div id="notice">Login successful</div>
206
+
207
+ <div title="UserController edit" class="form">
208
+ <h3>Edit user</h3>
209
+
210
+
211
+
212
+ <form action="/user/edit" method="post">
213
+
214
+
215
+ <div class = "user_edit"><table><tr class = "two_columns"><td class = "prompt"> <label> First Name: </label>
216
+ </td> <td class = "value"> <input id="user_firstname" name="user[firstname]" size="30" type="text" /> </td>
217
+ </tr><tr class = "two_columns"><td class = "prompt"> <label> Last Name: </label>
218
+ </td> <td class = "value"> <input id="user_lastname" name="user[lastname]" size="30" type="text" /> </td>
219
+ </tr><tr class = "two_columns"><td class = "prompt"> <label> Login ID: </label>
220
+ </td> <td class = "value"> <input id="user_login" name="user[login]" size="30" type="text" value="bob" /> </td>
221
+ </tr><tr class = "two_columns"><td class = "prompt"> <label> Email: </label>
222
+ </td> <td class = "value"> <input id="user_email" name="user[email]" size="30" type="text" value="bob@test.com" />
223
+ </td>
224
+ </tr></table>
225
+ <input name="submit" type="submit" value="Change Settings" />
226
+ </div>
227
+ </form>
228
+ <br/>
229
+ <form action="/user/change_password" method="post">
230
+ <input id="back_to" name="back_to" type="hidden" value="edit" />
231
+
232
+
233
+
234
+
235
+ <div class = "user_password"><table><tr class = "two_columns"><td class = "prompt"> <label> Password:
236
+ </label>
237
+ </td> <td class = "value"> <input id="user_password" name="user[password]" size="30" type="password" value="" />
238
+ </td>
239
+ </tr><tr class = "two_columns"><td class = "prompt"> <label> Password Confirmation: </label>
240
+ </td> <td class = "value"> <input id="user_password_confirmation" name="user[password_confirmation]" size="30" type="password" value="" /> </td>
241
+ </tr></table>
242
+ <input name="submit" type="submit" value="Change password" />
243
+
244
+ </div>
245
+ </form>
246
+
247
+ <form action="/user/delete" method="post">
248
+ <div class="user_delete">
249
+ <input id="user_form" name="user[form]" type="hidden" value="delete" />
250
+ <input name="submit" type="submit" value="Delete Account" />
251
+ </div>
252
+ </form>
253
+ </div>
254
+ </div>
255
+ </body>
256
+ </html>
257
+
258
+ EOF
259
+ post :edit, :user => { "firstname" => "Bob", "form" => "edit" }
260
+ assert_equal @response.session[:user].firstname, "Bob"
261
+
262
+ post :edit, :user => { "firstname" => "", "form" => "edit" }
263
+ assert_equal @response.session[:user].firstname, ""
264
+
265
+ get :logout
266
+ end
267
+ end