Fix #498 (cannot login using mobile interface) by introducing a login page specialized for mobile devices. To support this, I added named routes for the login paths and pulled up the mobile content negotiation code to the ApplicationController.

git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@531 a4c988fc-2ded-0310-b66e-134b36920a42
This commit is contained in:
lukemelia 2007-04-16 02:19:20 +00:00
parent fd5b871839
commit 14f2067a1e
7 changed files with 76 additions and 54 deletions

View file

@ -14,11 +14,12 @@ class ApplicationController < ActionController::Base
helper :application
include LoginSystem
layout 'standard'
layout proc{ |controller| controller.mobile? ? "mobile" : "standard" }
before_filter :set_session_expiration
prepend_before_filter :login_required
prepend_before_filter :enable_mobile_content_negotiation
after_filter :restore_content_type_for_mobile
after_filter :set_charset
include ActionView::Helpers::TextHelper
@ -116,6 +117,37 @@ class ApplicationController < ActionController::Base
Hash[*projects.reject{ |p| p.default_context.nil? }.map{ |p| [p.name, p.default_context.name] }.flatten].to_json
end
# Here's the concept behind this "mobile content negotiation" hack:
# In addition to the main, AJAXy Web UI, Tracks has a lightweight
# low-feature 'mobile' version designed to be suitablef or use
# from a phone or PDA. It makes some sense that tne pages of that
# mobile version are simply alternate representations of the same
# Todo resources. The implementation goal was to treat mobile
# as another format and be able to use respond_to to render both
# versions. Unfortunately, I ran into a lot of trouble simply
# registering a new mime type 'text/html' with format :m because
# :html already is linked to that mime type and the new
# registration was forcing all html requests to be rendered in
# the mobile view. The before_filter and after_filter hackery
# below accomplishs that implementation goal by using a 'fake'
# mime type during the processing and then setting it to
# 'text/html' in an 'after_filter' -LKM 2007-04-01
def mobile?
return params[:format] == 'm' || response.content_type == MOBILE_CONTENT_TYPE
end
def enable_mobile_content_negotiation
if mobile?
request.accepts.unshift(Mime::Type::lookup(MOBILE_CONTENT_TYPE))
end
end
def restore_content_type_for_mobile
if mobile?
response.content_type = 'text/html'
end
end
protected
def admin_login_required
@ -126,7 +158,10 @@ class ApplicationController < ActionController::Base
end
def redirect_back_or_home
redirect_back_or_default home_url
respond_to do |format|
format.html { redirect_back_or_default home_url }
format.m { redirect_back_or_default mobile_url }
end
end
def boolean_param(param_name)

View file

@ -1,6 +1,6 @@
class LoginController < ApplicationController
layout 'login'
layout 'login'
skip_before_filter :set_session_expiration
skip_before_filter :login_required
before_filter :get_current_user
@ -20,6 +20,7 @@ class LoginController < ApplicationController
notify :notice, "Login successful: session #{msg}"
cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year }
redirect_back_or_home
return
else
@login = params['user_login']
notify :warning, "Login unsuccessful"
@ -27,8 +28,13 @@ class LoginController < ApplicationController
when :get
if User.no_users_yet?
redirect_to :controller => 'users', :action => 'new'
return
end
end
respond_to do |format|
format.html
format.m { render :action => 'login_mobile.rhtml', :layout => 'mobile' }
end
end
def begin
@ -44,10 +50,13 @@ class LoginController < ApplicationController
# to the server using the redirect_url the library created for us.
# redirect to the server
redirect_to open_id_response.redirect_url((request.protocol + request.host_with_port + "/"), url_for(:action => 'complete'))
respond_to do |format|
format.html { redirect_to open_id_response.redirect_url((request.protocol + request.host_with_port + "/"), open_id_complete_url) }
format.m { redirect_to open_id_response.redirect_url((request.protocol + request.host_with_port + "/"), formatted_open_id_complete_url(:format => 'm')) }
end
else
notify :warning, "Unable to find openid server for <q>#{openid_url}</q>"
redirect_to :action => 'login'
redirect_to_login
end
end
@ -92,14 +101,14 @@ class LoginController < ApplicationController
else
notify :warning, "Unknown response status: #{open_id_response.status}"
end
redirect_to :action => 'login' unless performed?
redirect_to_login unless performed?
end
def logout
session['user_id'] = nil
reset_session
notify :notice, "You have been logged out of Tracks."
redirect_to :action => "login"
redirect_to_login
end
def check_expiry
@ -122,6 +131,13 @@ class LoginController < ApplicationController
private
def redirect_to_login
respond_to do |format|
format.html { redirect_to login_path }
format.m { redirect_to formatted_login_path(:format => 'm') }
end
end
def should_expire_sessions?
session['noexpiry'] != "on"
end

View file

@ -7,13 +7,8 @@ class TodosController < ApplicationController
append_before_filter :init, :except => [ :destroy, :completed, :completed_archive, :check_deferred ]
append_before_filter :get_todo_from_params, :only => [ :edit, :toggle_check, :show, :update, :destroy ]
prepend_before_filter :enable_mobile_content_negotiation
after_filter :restore_content_type_for_mobile
session :off, :only => :index, :if => Proc.new { |req| is_feed_request(req) }
layout proc{ |controller| controller.mobile? ? "mobile" : "standard" }
def index
@projects = @user.projects.find(:all, :include => [ :todos ])
@contexts = @user.contexts.find(:all, :include => [ :todos ])
@ -317,40 +312,8 @@ class TodosController < ApplicationController
end
# Here's the concept behind this "mobile content negotiation" hack:
# In addition to the main, AJAXy Web UI, Tracks has a lightweight
# low-feature 'mobile' version designed to be suitablef or use
# from a phone or PDA. It makes some sense that tne pages of that
# mobile version are simply alternate representations of the same
# Todo resources. The implementation goal was to treat mobile
# as another format and be able to use respond_to to render both
# versions. Unfortunately, I ran into a lot of trouble simply
# registering a new mime type 'text/html' with format :m because
# :html already is linked to that mime type and the new
# registration was forcing all html requests to be rendered in
# the mobile view. The before_filter and after_filter hackery
# below accomplishs that implementation goal by using a 'fake'
# mime type during the processing and then setting it to
# 'text/html' in an 'after_filter' -LKM 2007-04-01
def mobile?
return params[:format] == 'm' || response.content_type == MOBILE_CONTENT_TYPE
end
def enable_mobile_content_negotiation
if mobile?
request.accepts.unshift(Mime::Type::lookup(MOBILE_CONTENT_TYPE))
end
end
def restore_content_type_for_mobile
if mobile?
response.content_type = 'text/html'
end
end
private
def get_todo_from_params
@todo = @user.todos.find(params['id'])
end

View file

@ -35,7 +35,7 @@
page.select('.notes').each { |e| e.toggle }
end
-%>&nbsp;|&nbsp;
<%= link_to "Logout (#{@user.display_name}) »", :controller => "login", :action=>"logout"%>
<%= link_to "Logout (#{@user.display_name}) »", logout_path %>
</div>
<div id="navcontainer">

View file

@ -3,4 +3,4 @@
<hr />
<%= render :partial => 'mobile_actions' %>
<hr />
<%= link_to "Logout", :controller => 'login', :action => 'logout' %>
<%= link_to "Logout", formatted_logout_path(:format => 'm') %>

View file

@ -2,8 +2,16 @@ ActionController::Routing::Routes.draw do |map|
UJS::routes
# Login Routes
map.connect 'login', :controller => 'login', :action => 'login'
map.connect 'logout', :controller => 'login', :action => 'logout'
map.with_options :controller => 'login' do |login|
login.login 'login', :action => 'login'
login.formatted_login 'login.:format', :action => 'login'
login.logout 'logout', :action => 'logout'
login.formatted_logout 'logout.:format', :action => 'logout'
login.open_id_begin 'begin', :action => 'begin'
login.formatted_open_id_begin 'begin.:format', :action => 'begin'
login.open_id_complete 'complete', :action => 'complete'
login.formatted_open_id_complete 'complete.:format', :action => 'complete'
end
map.resources :users,
:member => {:change_password => :get, :update_password => :post,

View file

@ -113,8 +113,8 @@ module LoginSystem
# a popup window might just close itself for instance
def access_denied
respond_to do |format|
format.html { redirect_to :controller=>"login", :action =>"login" }
format.m { redirect_to :controller=>"login", :action =>"login" }
format.html { redirect_to login_path }
format.m { redirect_to formatted_login_path(:format => 'm') }
format.js { render :partial => 'login/redirect_to_login' }
format.xml { basic_auth_denied }
format.rss { basic_auth_denied }