amrita2 1.9.6 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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