merge 19889:20181 of rails_port into the openID branch
authorKai Krueger <kakrueger@gmail.com>
Sat, 27 Feb 2010 11:21:15 +0000 (11:21 +0000)
committerKai Krueger <kakrueger@gmail.com>
Sat, 27 Feb 2010 11:21:15 +0000 (11:21 +0000)
merge conflicts with the remember_me functionality

1  2 
app/controllers/user_controller.rb
app/models/user.rb
app/views/user/account.html.erb
app/views/user/login.html.erb
config/locales/en.yml

index f9bbd5dd5be7c9fbeeb97c5b73bd03e2c06e7185,c181da305862f81bdd721fb9098d154f98e46b90..97e184b5943cef9269668e13520893f6867b9375
@@@ -24,78 -24,21 +24,79 @@@ class UserController < ApplicationContr
      if Acl.find_by_address(request.remote_ip, :conditions => {:k => "no_account_creation"})
        render :action => 'new'
      else
-         #The redirect from the OpenID provider reenters here again
-         #and we need to pass the parameters through to the 
-         #open_id_authentication function a second time
-         if params[:open_id_complete]
-               openid_verify('', true)
-               #We have set the user.openid_url to nil beforehand. If it hasn't
-               #been set to a new valid openid_url, it means the openid couldn't be validated
-               if @user.nil? or @user.openid_url.nil?
-                 render :action => 'new'
-                 return
-               end  
-         else
-               @user = User.new(params[:user])
-               
-               @user.visible = true
-               @user.data_public = true
-               @user.description = "" if @user.description.nil?
-               @user.creation_ip = request.remote_ip
-               @user.languages = request.user_preferred_languages
-               #Set the openid_url to nil as for one it is used
-               #to check if the openid could be validated and secondly
-               #to not get dupplicate conflicts for an empty openid 
-               @user.openid_url = nil
-               if (!params[:user][:openid_url].nil? and params[:user][:openid_url].length > 0)
++        #The redirect from the OpenID provider reenters here again 
++      #and we need to pass the parameters through to the  
++      #open_id_authentication function a second time 
++      if params[:open_id_complete] 
++        openid_verify('', true) 
++        #We have set the user.openid_url to nil beforehand. If it hasn't 
++        #been set to a new valid openid_url, it means the openid couldn't be validated 
++        if @user.nil? or @user.openid_url.nil? 
++          render :action => 'new' 
++          return 
++        end   
++      else
+       @user = User.new(params[:user])
+       @user.visible = true
+       @user.data_public = true
+       @user.description = "" if @user.description.nil?
+       @user.creation_ip = request.remote_ip
+       @user.languages = request.user_preferred_languages
++        #Set the openid_url to nil as for one it is used 
++        #to check if the openid could be validated and secondly 
++        #to not get dupplicate conflicts for an empty openid  
++        @user.openid_url = nil
++
++if (!params[:user][:openid_url].nil? and params[:user][:openid_url].length > 0)
 +                if @user.pass_crypt.length == 0 
 +            #if the password is empty, but we have a openid 
 +            #then generate a random passowrd to disable 
 +            #loging in via password 
 +            @user.pass_crypt = ActiveSupport::SecureRandom.base64(16) 
 +            @user.pass_crypt_confirmation = @user.pass_crypt 
 +          end
 +                #Validate all of the other fields before
 +                #redirecting to the openid provider
 +                if !@user.valid?
 +                      render :action => 'new'
 +                else            
 +                      #TODO: Is it a problem to store the user variable with respect to password safty in the session variables?
 +                      #Store the user variable in the session for it to be accessible when redirecting back from the openid provider
 +                      session[:new_usr] = @user
 +                      begin
 +                        @norm_openid_url = OpenIdAuthentication.normalize_identifier(params[:user][:openid_url])
 +                      rescue
 +                        flash.now[:error] = t 'user.login.openid invalid'
 +                        render :action => 'new'
 +                        return
 +                      end
 +                      #Verify that the openid provided is valid and that the user is the owner of the id
 +                      openid_verify(@norm_openid_url, true)
 +                      #openid_verify can return in two ways:
 +                      #Either it returns with a redirect to the openid provider who then freshly
 +                      #redirects back to this url if the openid is valid, or if the openid is not plausible
 +                      #and no provider for it could be found it just returns
 +                      #we want to just let the redirect through
 +                      if response.headers["Location"].nil?
 +                        render :action => 'new'
 +                      end
 +                end
 +                #At this point there was either an error and the page has been rendered,
 +                #or there is a redirect to the openid provider and the rest of the method
 +                #gets executed whenn this method gets reentered after redirecting back
 +                #from the openid provider
 +                return
 +              end
 +        end
-         if @user.save
-               flash[:notice] = t 'user.new.flash create success message'
-               Notifier.deliver_signup_confirm(@user, @user.tokens.create(:referer => params[:referer]))
-               redirect_to :action => 'login'
-         else
-               render :action => 'new'
-         end
+       if @user.save
+         flash[:notice] = t 'user.new.flash create success message'
+         Notifier.deliver_signup_confirm(@user, @user.tokens.create(:referer => params[:referer]))
+         redirect_to :action => 'login'
+       else
+         render :action => 'new'
+       end
      end
    end
  
      @title = t 'user.account.title'
      @tokens = @user.oauth_tokens.find :all, :conditions => 'oauth_tokens.invalidated_at is null and oauth_tokens.authorized_at is not null'
  
-     #The redirect from the OpenID provider reenters here again
++      #The redirect from the OpenID provider reenters here again
 +    #and we need to pass the parameters through to the 
 +    #open_id_authentication function
 +    if params[:open_id_complete]
 +      openid_verify('', false)
 +        @user.save
 +      return
 +    end
 +
      if params[:user] and params[:user][:display_name] and params[:user][:description]
-       if params[:user][:email] != @user.email
-         @user.new_email = params[:user][:email]
-       end
        @user.display_name = params[:user][:display_name]
+       @user.new_email = params[:user][:new_email]
  
        if params[:user][:pass_crypt].length > 0 or params[:user][:pass_crypt_confirmation].length > 0
          @user.pass_crypt = params[:user][:pass_crypt]
        if @user.save
          set_locale
  
-         if params[:user][:email] == @user.new_email
-           flash.now[:notice] = t 'user.account.flash update success confirm needed'
-           Notifier.deliver_email_confirm(@user, @user.tokens.create)
-         else
+         if @user.new_email.nil? or @user.new_email.empty?
            flash.now[:notice] = t 'user.account.flash update success'
+         else
+           flash.now[:notice] = t 'user.account.flash update success confirm needed'
+           begin
+             Notifier.deliver_email_confirm(@user, @user.tokens.create)
+           rescue
+             # Ignore errors sending email
+           end
          end
        end
-       if (params[:user][:openid_url].length > 0)
 +
++        if (params[:user][:openid_url].length > 0)
 +              begin
 +                @norm_openid_url = OpenIdAuthentication.normalize_identifier(params[:user][:openid_url])
 +                if (@norm_openid_url != @user.openid_url)
 +                      #If the OpenID has changed, we want to check that it is a valid OpenID and one
 +                      #the user has control over before saving the openID as a password equivalent for
 +                      #the user.
 +                      openid_verify(@norm_openid_url, false)
 +                end
 +              rescue
 +                flash.now[:error] = t 'user.login.openid invalid'
 +              end
 +      end
 +
+     else
+       if flash[:errors]
+         flash[:errors].each do |attr,msg|
+           attr = "new_email" if attr == "email"
+           @user.errors.add(attr,msg)
+         end
+       end
      end
    end
  
-   def set_home
-     if params[:user][:home_lat] and params[:user][:home_lon]
-       @user.home_lat = params[:user][:home_lat].to_f
-       @user.home_lon = params[:user][:home_lon].to_f
-       if @user.save
-         flash[:notice] = t 'user.set_home.flash success'
-         redirect_to :controller => 'user', :action => 'account'
 +  def openid_specialcase_mapping(openid_url)
 +    #Special case gmail.com, as it is pontentially a popular OpenID provider and unlike
 +    #yahoo.com, where it works automatically, Google have hidden their OpenID endpoint
 +    #somewhere obscure making it less userfriendly.
 +    if (openid_url.match(/(.*)gmail.com(\/?)$/) or openid_url.match(/(.*)googlemail.com(\/?)$/) )
 +      return 'https://www.google.com/accounts/o8/id'
 +    end
 +
 +    return nil
 +  end  
 +
 +  def openid_verify(openid_url,account_create)
 +    authenticate_with_open_id(openid_url) do |result, identity_url|
 +      if result.successful?
 +        #We need to use the openid url passed back from the OpenID provider
 +        #rather than the one supplied by the user, as these can be different.
 +        #e.g. one can simply enter yahoo.com in the login box, i.e. no user specific url
 +        #only once it comes back from the OpenID provider do we know the unique address for
 +        #the user.
 +              @user = session[:new_usr] unless @user #this is used for account creation when the user is not yet in the database
 +        @user.openid_url = identity_url
 +        elsif result.missing?
 +              mapped_id = openid_specialcase_mapping(openid_url)
 +              if mapped_id
 +                openid_verify(mapped_id, account_create)
 +              else
 +                flash.now[:error] = t 'user.login.openid missing provider'
 +              end
 +        elsif result.invalid?
 +              flash.now[:error] = t 'user.login.openid invalid'
 +        else
 +              flash.now[:error] = t 'user.login.auth failure'
 +        end
 +    end
 +  end
 +
++  def open_id_authentication(openid_url)
++    #TODO: only ask for nickname and email, if we don't already have a user for that openID, in which case
++    #email and nickname are already filled out. I don't know how to do that with ruby syntax though, as we
++    #don't want to duplicate the do block
++    #On the other hand it also doesn't matter too much if we ask every time, as the OpenID provider should
++    #remember these results, and shouldn't repromt the user for these data each time.
++    authenticate_with_open_id(openid_url, :return_to => request.protocol + request.host_with_port + '/login?referer=' + params[:referer], :optional => [:nickname, :email]) do |result, identity_url, registration|
++      if result.successful?
++        #We need to use the openid url passed back from the OpenID provider
++        #rather than the one supplied by the user, as these can be different.
++        #e.g. one can simply enter yahoo.com in the login box, i.e. no user specific url
++        #only once it comes back from the OpenID provider do we know the unique address for
++        #the user.
++        user = User.find_by_openid_url(identity_url)
++        if user
++          if user.visible? and user.active?
++            session[:user] = user.id
++                      session_expires_after 1.month if session[:remember]
++          else
++            user = nil
++            flash.now[:error] = t 'user.login.account not active'
++          end
++        else
++          #We don't have a user registered to this OpenID. Redirect to the create account page
++          #with username and email filled in if they have been given by the OpenID provider through
++          #the simple registration protocol
++          redirect_to :controller => 'user', :action => 'new', :nickname => registration['nickname'], :email => registration['email'], :openid => identity_url
++        end
++      else if result.missing?
++             #Try and apply some heuristics to make common cases more userfriendly
++             mapped_id = openid_specialcase_mapping(openid_url)
++             if mapped_id
++               open_id_authentication(mapped_id)
++             else
++               flash.now[:error] = t 'user.login.openid missing provider'
++             end
++           else if result.invalid?
++                  flash.now[:error] = t 'user.login.openid invalid'
++                else
++                  flash.now[:error] = t 'user.login.auth failure'
++                end
++           end
 +      end
 +    end
 +  end
 +
    def go_public
      @user.data_public = true
      @user.save
      # The user is logged in already, so don't show them the signup page, instead
      # send them to the home page
      redirect_to :controller => 'site', :action => 'index' if session[:user]
-     @nickname = params['nickname']
 +
++      @nickname = params['nickname']
 +    @email = params['email']
 +      @openID = params['openid']
    end
  
    def login
-     #The redirect from the OpenID provider reenters here again
 +
-     
++      #The redirect from the OpenID provider reenters here again
 +    #and we need to pass the parameters through to the 
 +    # open_id_authentication function
 +    if params[:open_id_complete]
 +      open_id_authentication('')
 +    end
 +
      if params[:user] and session[:user].nil?
-       if !params[:user][:openid_url].nil? and !params[:user][:openid_url].empty?
 -      email_or_display_name = params[:user][:email]
 -      pass = params[:user][:password]
 -      user = User.authenticate(:username => email_or_display_name, :password => pass)
 -      if user
 -        session[:user] = user.id
 -        session_expires_after 1.month if params[:remember_me]
 -      elsif User.authenticate(:username => email_or_display_name, :password => pass, :inactive => true)
 -        flash.now[:error] = t 'user.login.account not active'
++        if !params[:user][:openid_url].nil? and !params[:user][:openid_url].empty?
++              session[:remember] = params[:remember_me]
 +        open_id_authentication(params[:user][:openid_url])
        else
-         email_or_display_name = params[:user][:email]
-         pass = params[:user][:password]
-         user = User.authenticate(:username => email_or_display_name, :password => pass)
-         if user
-           session[:user] = user.id
-         elsif User.authenticate(:username => email_or_display_name, :password => pass, :inactive => true)
-           flash.now[:error] = t 'user.login.account not active'
-         else
-           flash.now[:error] = t 'user.login.auth failure'
-         end
 -        flash.now[:error] = t 'user.login.auth failure'
--      end
++              email_or_display_name = params[:user][:email]
++              pass = params[:user][:password]
++              user = User.authenticate(:username => email_or_display_name, :password => pass)
++              if user
++                session[:user] = user.id
++                session_expires_after 1.month if params[:remember_me]
++              elsif User.authenticate(:username => email_or_display_name, :password => pass, :inactive => true)
++                flash.now[:error] = t 'user.login.account not active'
++              else
++                flash.now[:error] = t 'user.login.auth failure'
++              end
++        end
      end
-   
      if session[:user]
        # The user is logged in, if the referer param exists, redirect them to that
        # unless they've also got a block on them, in which case redirect them to
index eb69dc03148107bc4bd8092382db1b5634957135,0b8b512ee3bab5becf3bc350fb916026bd51b5b0..1a476954440f8b308be08c63c0ed8072dd7c5e03
@@@ -22,11 -22,10 +22,11 @@@ class User < ActiveRecord::Bas
    validates_confirmation_of :pass_crypt#, :message => ' must match the confirmation password'
    validates_uniqueness_of :display_name, :allow_nil => true
    validates_uniqueness_of :email
 +  validates_uniqueness_of :openid_url, :allow_nil => true
    validates_length_of :pass_crypt, :within => 8..255
    validates_length_of :display_name, :within => 3..255, :allow_nil => true
-   validates_length_of :email, :within => 6..255
-   validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
+   validates_email_format_of :email
+   validates_email_format_of :new_email, :allow_blank => true
    validates_format_of :display_name, :with => /^[^\/;.,?]*$/
    validates_numericality_of :home_lat, :allow_nil => true
    validates_numericality_of :home_lon, :allow_nil => true
index 99d0f216e9fe1a675b414fcda1ed584ac2c184f4,881750c36504a2264c475258adf9770fd5bf9dcf..c20f3526c69103aa9da24c5a0f525c1885c6ac91
  <h2><%= t 'user.account.my settings' %></h2>
  <%= error_messages_for 'user' %>
- <% form_for :user, @user do |f| %>
+ <% form_for :user, :html => { :multipart => true } do |f| %>
  <table id="accountForm">
-   <tr><td class="fieldName"><%= t 'user.new.display name' %></td><td><%= f.text_field :display_name %></td></tr>
-   <tr><td class="fieldName"><%= t 'user.new.email address' %></td><td><%= f.text_field :email, {:size => 50, :maxlength => 255} %> <span class="minorNote"><%= t 'user.account.email never displayed publicly' %></span></td></tr>
-   <tr><td class="fieldName" style="padding-bottom:0px;"><%= t 'user.new.password' %></td><td style="padding-bottom:0px;"><%= f.password_field :pass_crypt, {:value => '', :size => 30, :maxlength => 255} %></td></tr>
-   <tr><td class="fieldName" style="padding-bottom:0px;"><%= t 'user.new.confirm password' %></td><td><%= f.password_field :pass_crypt_confirmation, {:value => '', :size => 30, :maxlength => 255} %></td></tr>
-   <tr><td class="fieldName" ><%= t 'user.account.openid.openid' %></td><td style="padding-bottom:0px;"><%= f.text_field :openid_url %> (<a href="<%= t 'user.account.openid.link' %>" target="_new"><%= t 'user.account.openid.link text' %></a>) </td></tr>
-   <tr>
-   <td class="fieldName" valign="top"><%= t 'user.account.public editing.heading' %></td>
-   <td>
- <% if @user.data_public? %>
-   <%= t 'user.account.public editing.enabled' %> <span class="minorNote">(<a href="<%= t 'user.account.public editing.enabled link' %>" target="_new"><%= t 'user.account.public editing.enabled link text' %></a>)</span>
- <% else %>
-   <%= t 'user.account.public editing.disabled' %><span class="minorNote">(<a href="#public"><%= t 'user.account.public editing.disabled link text' %></a>)</span>
- <% end %>
-   </td>
+   <tr>
+     <td class="fieldName"><%= t 'user.new.display name' %></td>
+     <td><%= f.text_field :display_name %></td>
+   </tr>
 -
+   <tr>
+     <td class="fieldName" style="padding-bottom:0px;"><%= t 'user.account.current email address' %></td>
+     <td style="padding-bottom:0px;"><%= @user.email %> <span class="minorNote"><%= t 'user.account.email never displayed publicly' %></span></td>
+   </tr>
+   <tr>
+     <td class="fieldName"><%= t 'user.account.new email address' %></td>
+     <td><%= f.text_field :new_email, {:size => 50, :maxlength => 255} %> <span class="minorNote"><%= t 'user.account.email never displayed publicly' %></span></td>
+   </tr>
+   <tr>
+     <td class="fieldName" style="padding-bottom:0px;"><%= t 'user.new.password' %></td>
+     <td style="padding-bottom:0px;"><%= f.password_field :pass_crypt, {:value => '', :size => 30, :maxlength => 255} %></td>
+   </tr>
+   <tr>
+     <td class="fieldName"><%= t 'user.new.confirm password' %></td>
+     <td><%= f.password_field :pass_crypt_confirmation, {:value => '', :size => 30, :maxlength => 255} %></td>
+   </tr>
++  <tr>
++    <td class="fieldName" ><%= t 'user.account.openid.openid' %></td>
++    <td style="padding-bottom:0px;"><%= f.text_field :openid_url %> (<a href="<%= t 'user.account.openid.link' %>" target="_new"><%= t 'user.account.openid.link text' %></a>) </td>
++</tr>
+   <tr>
+     <td class="fieldName" valign="top"><%= t 'user.account.public editing.heading' %></td>
+     <td>
+       <% if @user.data_public? %>
+         <%= t 'user.account.public editing.enabled' %> <span class="minorNote">(<a href="<%= t 'user.account.public editing.enabled link' %>" target="_new"><%= t 'user.account.public editing.enabled link text' %></a>)</span>
+       <% else %>
+         <%= t 'user.account.public editing.disabled' %> <span class="minorNote">(<a href="#public"><%= t 'user.account.public editing.disabled link text' %></a>)</span>
+       <% end %>
+     </td>
+   </tr>
+   <tr>
+     <td class="fieldName" valign="top"><%= t 'user.account.profile description' %></td>
+     <td><%= f.text_area :description, :rows => '5', :cols => '60' %></td>
    </tr>
  
-   <tr><td class="fieldName" valign="top"><%= t 'user.account.profile description' %></td><td><%= f.text_area :description, :rows => '5', :cols => '60' %></td></tr>
+   <tr>
+     <td class="fieldName" valign="top"><%= t 'user.account.preferred languages' %></td>
+     <td><%= f.text_field :languages %></td>
+   </tr>
  
-   <tr><td class="fieldName" valign="top"><%= t 'user.account.preferred languages' %></td><td><%= f.text_field :languages %></td></tr>
+   <tr>
+     <td class="fieldName" valign="top">
+       <%= t 'user.account.image' %>
+     </td>
+     <td valign="top">
+       <% if @user.image.nil? %>
+         <%= hidden_field_tag "image_action", "new" %>
+         <%= t 'user.account.new image' %><br /><%= file_column_field "user", "image" %>
+       <% else %>
+         <table>
+           <tr>
+             <td rowspan="3" valign="top"><%= image_tag url_for_file_column(@user, "image") %></td>
+             <td><%= radio_button_tag "image_action", "keep", true %></td>
+             <td><%= t 'user.account.keep image' %></td>
+           </tr>
+           <tr>
+             <td><%= radio_button_tag "image_action", "delete" %></td>
+             <td><%= t 'user.account.delete image' %></td>
+           </tr>
+           <tr>
+             <td><%= radio_button_tag "image_action", "new" %></td>
+             <td><%= t 'user.account.replace image' %><br /><%= file_column_field "user", "image", :onchange => "$('image_action_new').checked = true" %></td>
+           </tr>
+         </table>
+       <% end %>
+     </td>
+   </tr>
  
-   <tr id="homerow" <% unless @user.home_lat and @user.home_lon %> class="nohome" <%end%> ><td class="fieldName"><%= t 'user.account.home location' %></td><td><em class="message"><%= t 'user.account.no home location' %></em><span class="location"><%= t 'user.account.latitude' %> <%= f.text_field :home_lat, :size => 20, :id => "home_lat" %><%= t 'user.account.longitude' %><%= f.text_field :home_lon, :size => 20, :id => "home_lon" %></span></td></tr>
+   <tr id="homerow" <% unless @user.home_lat and @user.home_lon %> class="nohome" <%end%> >
+     <td class="fieldName"><%= t 'user.account.home location' %></td>
+     <td><em class="message"><%= t 'user.account.no home location' %></em><span class="location"><%= t 'user.account.latitude' %> <%= f.text_field :home_lat, :size => 20, :id => "home_lat" %><%= t 'user.account.longitude' %><%= f.text_field :home_lon, :size => 20, :id => "home_lon" %></span></td>
+   </tr>
  
-   <tr><td></td><td>
-   <p><%= t 'user.account.update home location on click' %> <input type="checkbox" value="1" <% unless @user.home_lat and @user.home_lon %> checked="checked" <% end %> id="updatehome" /> </p>
-   <div id="map" style="border:1px solid black; position:relative; width:500px; height:400px;"></div>
-   </td></tr>
+   <tr>
+     <td></td>
+     <td>
+       <p><%= t 'user.account.update home location on click' %> <input type="checkbox" value="1" <% unless @user.home_lat and @user.home_lon %> checked="checked" <% end %> id="updatehome" /> </p>
+       <div id="map" style="border:1px solid black; position:relative; width:500px; height:400px;"></div>
+     </td>
+   </tr>
    
-   <tr><td></td><td align=right><br/><%= submit_tag t('user.account.save changes button') %></td></tr>
+   <tr>
+     <td></td>
+     <td align=right><br/><%= submit_tag t('user.account.save changes button') %></td>
+   </tr>
  </table>
- <br/>
  <% end %>
  
  <%= render :partial => 'friend_map' %>
index 16d820b69c48144421900d37806b0143f35371cf,9ff10007905d26348d9397f2c0ae3af6c9689a3f..269bbc0cc6aeff99512132836d8603ddb16701b6
@@@ -6,16 -6,9 +6,12 @@@
  <%= hidden_field_tag('referer', h(params[:referer])) %>
  <table id="loginForm">
    <tr><td class="fieldName"><%= t 'user.login.email or username' %></td><td><%= text_field('user', 'email',{:size => 28, :maxlength => 255, :tabindex => 1}) %></td></tr>
--  <tr><td class="fieldName"><%= t 'user.login.password' %></td><td><%= password_field('user', 'password',{:size => 28, :maxlength => 255, :tabindex => 2}) %> <span class="minorNote">(<%= link_to t('user.login.lost password link'), :controller => 'user', :action => 'lost_password' %>)</span></td></tr>
- <tr><td colspan="2">&nbsp;<!--vertical spacer--></td></tr>
- <tr><td></td><td align="right"><%= submit_tag t('user.login.login_button'), :tabindex => 3 %></td></tr>
- <tr><td colspan = "3"><h4><%= t 'user.login.alternatively' %></h4></td></tr>
 -  <tr><td class="fieldName"><label for="remember_me">Remember me:</label></td><td><%= check_box_tag "remember_me", "yes", false, :tabindex => 3 %></td></tr> 
++  <tr><td class="fieldName"><%= t 'user.login.password' %></td><td><%= password_field('user', 'password',{:size => 28, :maxlength => 255, :tabindex => 2}) %></td><td> <span class="minorNote">(<%= link_to t('user.login.lost password link'), :controller => 'user', :action => 'lost_password' %>)</span></td></tr>
++<tr><td colspan = "3"><h4><I><%= t 'user.login.alternatively' %></I></h4></td></tr>
++<tr><td class="fieldName"><%= t 'user.login.openid' %></td><td><%= text_field('user', 'openid_url',{:size => 28, :maxlength => 255, :tabindex => 3}) %></td><td> <span class="minorNote">(<a href="<%= t 'user.account.openid.link' %>" target="_new"><%= t 'user.account.openid.link text' %></a>)</span></td></tr>
 +
- <tr><td colspan="2"><%= t 'user.login.openid description' %> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<a href="<%= t 'user.account.openid.link' %>" target="_new"><%= t 'user.account.openid.link text' %></a>)</td></tr>
- <tr><td class="fieldName"><%= t 'user.login.openid' %></td><td><%= text_field('user', 'openid_url',{:size => 28, :maxlength => 255, :tabindex => 3}) %></td></tr>
- <tr><td colspan="2">&nbsp;<!--vertical spacer--></td></tr>
- <tr><td></td><td align="right"><%= submit_tag t('user.login.login_button'), :tabindex => 3 %></td></tr>
++  <tr><td colspan="2">&nbsp;<!--vertical spacer--></td></tr>
+   <tr><td colspan="2">&nbsp;<!--vertical spacer--></td></tr>
 -  <tr><td></td><td align="right"><%= submit_tag t('user.login.login_button'), :tabindex => 3 %></td></tr>
++  <tr><td class="fieldName"><label for="remember_me">Remember me:</label></td><td><%= check_box_tag "remember_me", "yes", false, :tabindex => 3 %></td><td align=right><%= submit_tag t('user.login.login_button'), :tabindex => 3 %></td></tr>
  </table>
  <% end %>
index 58fca9498a6c6fd6b2be1b18dbb8c4faeaad40d4,e75cc22069d0680ec9ec7246cf01c838e3196ce5..b358cf8d3b9d1b684f4673f8d266e60d17119632
      account:
        title: "Edit account"
        my settings: My settings
+       current email address: "Current Email Address:"
+       new email address: "New Email Address:"
        email never displayed publicly: "(never displayed publicly)"
 +      openid:
 +        openid: "OpenID:"
 +        link: "http://wiki.openstreetmap.org/wiki/OpenID"
 +        link text: "what is this?"
        public editing:
          heading: "Public editing:"
          enabled: "Enabled. Not anonymous and can edit data."