diff options
author | francis <francis> | 2007-11-01 14:45:56 +0000 |
---|---|---|
committer | francis <francis> | 2007-11-01 14:45:56 +0000 |
commit | 9e08e323fcdcf763d76ede20807893f6bbfb7fbf (patch) | |
tree | 75862722c1aea384bebc0095e22ebb4cf387c6cd | |
parent | acbd0f3e2f47e5fd1d235dd8e12351b85a499eca (diff) |
Save post request properly into database with a model, as a record of where to
redirect back to after login.
Token generation for these saved logins.
-rw-r--r-- | app/controllers/application.rb | 19 | ||||
-rw-r--r-- | app/controllers/user_controller.rb | 41 | ||||
-rw-r--r-- | app/models/post_redirect.rb | 36 | ||||
-rw-r--r-- | app/views/layouts/default.rhtml | 2 | ||||
-rw-r--r-- | app/views/user_accounts/signin.rhtml | 1 | ||||
-rw-r--r-- | app/views/user_accounts/signup.rhtml | 9 | ||||
-rw-r--r-- | db/migrate/014_create_post_redirects.rb | 15 | ||||
-rw-r--r-- | db/schema.rb | 10 | ||||
-rw-r--r-- | spec/controllers/request_controller_spec.rb | 8 | ||||
-rw-r--r-- | test/fixtures/post_redirects.yml | 5 | ||||
-rw-r--r-- | test/unit/post_redirect_test.rb | 10 | ||||
-rw-r--r-- | todo.txt | 11 |
12 files changed, 129 insertions, 38 deletions
diff --git a/app/controllers/application.rb b/app/controllers/application.rb index 824f6f77b..fb56497f4 100644 --- a/app/controllers/application.rb +++ b/app/controllers/application.rb @@ -6,7 +6,7 @@ # Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved. # Email: francis@mysociety.org; WWW: http://www.mysociety.org/ # -# $Id: application.rb,v 1.21 2007-11-01 05:35:43 francis Exp $ +# $Id: application.rb,v 1.22 2007-11-01 14:45:56 francis Exp $ class ApplicationController < ActionController::Base @@ -21,9 +21,9 @@ class ApplicationController < ActionController::Base # Check the user is logged in def authenticated? unless session[:user] - session[:intended_uri] = request.request_uri - session[:intended_params] = params - redirect_to signin_url + post_redirect = PostRedirect.new(:uri => request.request_uri, :post_params => params) + post_redirect.save! + redirect_to signin_url(:token => post_redirect.token) return false end return true @@ -34,12 +34,13 @@ class ApplicationController < ActionController::Base return User.find(session[:user]) end - # Do a POST redirect. This is a nasty hack - we store the posted values to - # the controller, and when the GET redirect with "?post_redirect=1" - # happens, load them in. - def post_redirect(uri, params) + # Do a POST redirect. This is a nasty hack - we store the posted values in + # the session, and when the GET redirect with "?post_redirect=1" happens, + # load them in. + def do_post_redirect(uri, params) session[:post_redirect_params] = params - # XXX what is built in Ruby URI munging function? + # XXX what is the built in Ruby URI munging function that can do this + # choice of & vs. ? more elegantly than this dumb if statement? if uri.include?("?") uri += "&post_redirect=1" else diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index 084bbbc81..2f12c8319 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -4,7 +4,7 @@ # Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved. # Email: francis@mysociety.org; WWW: http://www.mysociety.org/ # -# $Id: user_controller.rb,v 1.7 2007-10-31 17:25:29 francis Exp $ +# $Id: user_controller.rb,v 1.8 2007-11-01 14:45:56 francis Exp $ class UserController < ApplicationController # XXX See controllers/application.rb simplify_url_part for reverse of expression in SQL below @@ -16,31 +16,35 @@ class UserController < ApplicationController def signin # The explict signin link uses this to store where it is to go back to if params[:r] - session[:intended_uri] = params[:r] - session[:intended_params] = nil + post_redirect = PostRedirect.new(:uri => params[:r], :post_params => {}) + post_redirect.save! + params[:token] = post_redirect.token end if not params[:user] # First time page is shown - render :template => 'user_accounts/signin' and return + render :template => 'user_accounts/signin' + return else @user = User.authenticate(params[:user][:email], params[:user][:password]) if @user # Successful login session[:user] = @user.id - post_redirect session[:intended_uri], session[:intended_params] and return + post_redirect = PostRedirect.find_by_token(params[:token]) + do_post_redirect post_redirect.uri, post_redirect.post_params + return else if User.find(:first, :conditions => [ "email = ?", params[:user][:email] ]) # Failed to authenticate flash[:error] = "Password not correct, please try again" @user = User.new(params[:user]) - render :template => 'user_accounts/signin' and return + render :template => 'user_accounts/signin' + return else - # "I am new to FOIFA" - session[:email] = params[:user][:email] - session[:password] = params[:user][:password] - session[:first_time] = true - redirect_to :action => 'signup' and return + # Create a new account + params[:first_time] = true + self.signup + return end end end @@ -48,25 +52,20 @@ class UserController < ApplicationController # Create new account form def signup - # Default to value saved from signin form - params[:user] ||= { :email => session[:email] } - params[:user] ||= { :password => session[:password] } - # Make the user and try to save it @user = User.new(params[:user]) if not @user.save # First time get to form (e.g. from signin) , don't show errors - if session[:first_time] - @first_time = true - @user.errors.clear - session[:first_time] = false - end + @first_time = params[:first_time] + @user.errors.clear if @first_time # Show the form render :template => 'user_accounts/signup' else # New user made, redirect back to where we were session[:user] = @user.id - post_redirect session[:intended_uri], session[:intended_params] and return + post_redirect = PostRedirect.find_by_token(params[:token]) + do_post_redirect post_redirect.uri, post_redirect.post_params + return end end diff --git a/app/models/post_redirect.rb b/app/models/post_redirect.rb new file mode 100644 index 000000000..ab1a365f9 --- /dev/null +++ b/app/models/post_redirect.rb @@ -0,0 +1,36 @@ +# models/postredirect.rb: +# Saves an HTTP POST request, so it can be redirected to later. +# For example, after registering / logging in. +# +# Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved. +# Email: francis@mysociety.org; WWW: http://www.mysociety.org/ +# +# $Id: post_redirect.rb,v 1.1 2007-11-01 14:45:56 francis Exp $ + +require 'openssl' # for random bytes function + +class PostRedirect < ActiveRecord::Base + # We store YAML version of POST parameters in the database + def post_params=(params) + self.post_params_yaml = params.to_yaml + end + def post_params + YAML.load(self.post_params_yaml) + end + + # Make the token + def after_initialize + if not self.token + bytes = OpenSSL::Random.random_bytes(12) + # XXX Ruby has some base function that can do base 62 or 32 more easily? + base64 = [bytes].pack("m9999").strip + base64.gsub("+", "a") + base64.gsub("/", "b") + base64.gsub("=", "c") + self.token = base64 + end + end + +end + + diff --git a/app/views/layouts/default.rhtml b/app/views/layouts/default.rhtml index 45e062f78..1cd853628 100644 --- a/app/views/layouts/default.rhtml +++ b/app/views/layouts/default.rhtml @@ -11,7 +11,7 @@ <a href="/">GovernmentSpy</a> <span id="beta">Beta</span> </h1> - <div id="tagline">Freeing your information from them</div> + <div id="tagline">It's your information. Free it from them.</div> </div> <ul id="navigation"> <li><%= link_to "All Requests", request_list_url %></li> diff --git a/app/views/user_accounts/signin.rhtml b/app/views/user_accounts/signin.rhtml index d390c7174..137de91b3 100644 --- a/app/views/user_accounts/signin.rhtml +++ b/app/views/user_accounts/signin.rhtml @@ -18,6 +18,7 @@ <p> <label for="submit"> </label> + <%= hidden_field_tag 'token', params[:token] %> <%= submit_tag "Sign in" %> </p> diff --git a/app/views/user_accounts/signup.rhtml b/app/views/user_accounts/signup.rhtml index 7d6abc907..dd779a0f3 100644 --- a/app/views/user_accounts/signup.rhtml +++ b/app/views/user_accounts/signup.rhtml @@ -1,8 +1,12 @@ <%= foi_error_messages_for :user %> <% form_tag({:action => "signup"}, {:id => "accountForm"}) do %> - <h1>Create a new account</h1> - + <% if @first_time %> + <div class="form_note"> + <h1>Register new account</h1> + </div> + <% end %> + <p> <label for="user_email" id="signin_email"><strong>E-mail:</strong></label> <%= text_field 'user', 'email', :size => 20 %> @@ -37,6 +41,7 @@ <p> <label for="submit"> </label> + <%= hidden_field_tag 'token', params[:token] %> <%= submit_tag "Sign in" %> </p> diff --git a/db/migrate/014_create_post_redirects.rb b/db/migrate/014_create_post_redirects.rb new file mode 100644 index 000000000..26c561dac --- /dev/null +++ b/db/migrate/014_create_post_redirects.rb @@ -0,0 +1,15 @@ +class CreatePostRedirects < ActiveRecord::Migration + def self.up + create_table :post_redirects do |t| + t.column :token, :text + t.column :uri, :text + t.column :post_params_yaml, :text + t.column :created_at, :datetime + t.column :updated_at, :datetime + end + end + + def self.down + drop_table :post_redirects + end +end diff --git a/db/schema.rb b/db/schema.rb index 8350f3943..1f0181d25 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -2,7 +2,7 @@ # migrations feature of ActiveRecord to incrementally modify your database, and # then regenerate this schema definition. -ActiveRecord::Schema.define(:version => 13) do +ActiveRecord::Schema.define(:version => 14) do create_table "incoming_messages", :force => true do |t| t.column "info_request_id", :integer @@ -29,6 +29,14 @@ ActiveRecord::Schema.define(:version => 13) do t.column "sent_at", :datetime end + create_table "post_redirects", :force => true do |t| + t.column "token", :text + t.column "uri", :text + t.column "post_params_yaml", :text + t.column "created_at", :datetime + t.column "updated_at", :datetime + end + create_table "public_bodies", :force => true do |t| t.column "name", :text t.column "short_name", :text diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb index 41ff2b6b6..7ba066ad2 100644 --- a/spec/controllers/request_controller_spec.rb +++ b/spec/controllers/request_controller_spec.rb @@ -74,7 +74,13 @@ describe RequestController, "when creating a new request" do post :create, :info_request => { :public_body_id => public_bodies(:geraldine_public_body).id, :title => "Why is your quango called Geraldine?"}, :outgoing_message => { :body => "This is a silly letter. It is too short to be interesting." } - response.should redirect_to(:controller => 'user', :action => 'signin') + # XXX yeuch - no other easy way of getting the token so we can check + # the redirect URL, as it is by definition opaque to the controller + # apart from in the place that it redirects to. + post_redirects = PostRedirect.find_by_sql("select * from post_redirects order by id desc limit 1") + post_redirects.size.should == 1 + post_redirect = post_redirects[0] + response.should redirect_to(:controller => 'user', :action => 'signin', :token => post_redirect.token) end it "should create the request and outgoing message and redirec to request page when input is good and somebody is logged in" do diff --git a/test/fixtures/post_redirects.yml b/test/fixtures/post_redirects.yml new file mode 100644 index 000000000..b49c4eb4e --- /dev/null +++ b/test/fixtures/post_redirects.yml @@ -0,0 +1,5 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html +one: + id: 1 +two: + id: 2 diff --git a/test/unit/post_redirect_test.rb b/test/unit/post_redirect_test.rb new file mode 100644 index 000000000..785f53170 --- /dev/null +++ b/test/unit/post_redirect_test.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class PostRedirectTest < Test::Unit::TestCase + fixtures :post_redirects + + # Replace this with your real tests. + def test_truth + assert true + end +end @@ -1,8 +1,8 @@ -Offline -======= +Online +====== Work out how to do controller/view integrated specs and add some -Change to will_paginate +Move things from views/user_accounts into views/user Next ==== @@ -24,6 +24,8 @@ Write some tests (using rspec) Migrate to will_paginate from classic_pagination +Replace all find :conditions with find_by_ + Tidying ======= @@ -43,6 +45,7 @@ Add SQL foreign keys to database schema http://www.redhillconsulting.com.au/rails_plugins.html#foreign_key_migrations http://rubyforge.org/projects/mig-constraints/ Call "delete from sessions where now() - updated_at > 3600" (one hour) or whatever + - take care about this if you're still keeping POST requests in sessions during login Do pretty error messages, e.g. on invalid public body name page etc. @@ -86,6 +89,8 @@ http://www.ordnancesurvey.co.uk/oswebsite/aboutus/foi/coiindex.html Maybe prepend letter for them with "this is FOI request blah" boilerplate? +Forgotten password link + Sources of public bodies ======================== |