Noosfero/noosfero

View on GitHub
app/controllers/public/account_controller.rb

Summary

Maintainability
F
3 days
Test Coverage
class AccountController < ApplicationController
  no_design_blocks

  before_action :login_required, :require_login_for_environment, only: [:activation_question, :accept_terms, :activate_enterprise, :change_password]
  before_action :redirect_if_logged_in, only: [:login, :signup, :activate]
  before_action :protect_from_spam, only: :signup
  before_action :check_activation_token, only: [:activate, :resend_activation_codes]

  protect_from_forgery except: [:login]

  include Captcha

  helper CustomFieldsHelper
  # say something nice, you goof!  something sweet.
  def index
    unless logged_in?
      render action: "index_anonymous"
    end
  end

  def activate
    @user = User.find_by(activation_code: params[:activation_token])

    if @user.nil?
      session[:notice] = _("We couldn't find an account to be activated. "\
                           "Maybe it is to be approved by an admin.")
      redirect_to action: :login
    end

    if request.post?
      if @user.activate(params[:short_activation_code])
        check_redirection
        session[:join] = params[:join] unless params[:join].blank?

        if @user.activated?
          session[:notice] = _("Your account was successfully activated!")
          self.current_user = @user
          go_to_initial_page
        else
          session[:notice] = _("Your account was activated, now wait until "\
                               "an administrator approves your account.")
          redirect_to controller: :home, action: :welcome,
                      template_id: @user.person.template.try(:id)
        end
      else
        session[:notice] = _("Looks like your activation code is not correct. "\
                             "Would you try again?")
        redirect_to action: :activate, activation_token: @user.activation_code
      end
    end
  rescue ActiveRecord::RecordInvalid
    session[:notice] = _("Something went wrong. You can try again, and if it "\
                         "persists, contact an administrator.")
    redirect_to action: :activate, activation_token: @user.activation_code
  end

  def resend_activation_codes
    @user = User.find_by(activation_code: params[:activation_token])
    unless @user.present?
      session[:notice] = _("Invalid activation token. Maybe this account "\
                           "was already activated?")
      redirect_to action: :login
      return
    end

    @user.resend_activation_code
    session[:notice] = _("A new activation code is on its way. Make sure to "\
                         "use the last code you received.")
    redirect_to action: :activate, activation_token: @user.activation_code
  end

  # action to perform login to the application
  def login
    store_location(request.referer) unless params[:return_to] || session[:return_to]

    return unless request.post?

    self.current_user = plugins_alternative_authentication

    begin
      self.current_user ||= User.authenticate(params[:user][:login], params[:user][:password], environment) if params[:user]
    rescue User::UserNotActivated => e
      if e.user.activation_code.present?
        redirect_to action: :activate, activation_token: e.user.activation_code
      else
        session[:notice] = _("An admin will approve your account soon.")
        redirect_to action: :login
      end
      return
    end

    if logged_in?
      check_join_in_community(self.current_user)

      if params[:remember_me] == "1"
        self.current_user.remember_me
        cookies[:auth_token] = { value: self.current_user.remember_token, expires: self.current_user.remember_token_expires_at }
      end

      if redirect?
        go_to_initial_page
        session[:notice] = _("Logged in successfully")
      end
    else
      session[:notice] = _("Incorrect username or password") if redirect?
    end
  end

  def logout_popup
    render action: "logout_popup", layout: false
  end

  def login_popup
    @user = User.new
    render action: "login", layout: false
  end

  # action to register an user to the application
  def signup
    if @plugins.dispatch(:allow_user_registration).include?(false)
      redirect_back_or_default(controller: "home")
      session[:notice] = _("This environment doesn't allow user registration.")
      return
    end

    store_location(request.referer) unless params[:return_to] || session[:return_to]

    @invitation_code = params[:invitation_code]
    begin
      @user = User.build(params[:user], params[:profile_data].to_h, environment)
      @user.session = session
      @terms_of_use = environment.terms_of_use
      @user.return_to = session[:return_to]
      @person = Person.new(params[:profile_data])
      @person.environment = @user.environment
      @kinds = environment.kinds.where(type: "Person")

      if request.post?
        if verify_captcha(:signup, @user, nil, environment)
          @user.community_to_join = session[:join]
          @user.signup!
          invitation = Task.from_code(@invitation_code).first
          if invitation
            invitation.update! friend: @user.person
            invitation.finish
          end

          unless params[:file].nil?
            image = Image::new uploaded_data: params[:file][:image]

            @user.person.image = image
            @user.person.save
          end

          if @user.activated?
            self.current_user = @user
            check_join_in_community(@user)
            go_to_signup_initial_page
          else
            redirect_to action: :activate,
                        activation_token: @user.activation_code,
                        return_to: { controller: :home, action: :welcome,
                                     template_id: @user.person.template.try(:id) }
          end
        end
      end
    rescue ActiveRecord::RecordInvalid
      @person.valid?
      @person.errors.delete(:identifier)
      @person.errors.delete(:user_id)
      render action: "signup"
    end
  end

  # action to perform logout from the application
  def logout
    if logged_in?
      self.current_user.forget_me
      current_user.update({ chat_status_at: DateTime.now }.merge(last_chat_status: current_user.chat_status, chat_status: "offline"))
    end
    reset_session
    session[:notice] = _("You have been logged out.")
    redirect_to controller: "home", action: "index"
  end

  def change_password
    if request.post?
      @user = current_user
      begin
        @user.change_password!(params[:current_password],
                               params[:new_password],
                               params[:new_password_confirmation])
        session[:notice] = _("Your password has been changed successfully!")
        redirect_to action: "index"
      rescue Exception
      end
    end
  end

  include ForgotPasswordHelper
  helper :forgot_password

  def forgot_password
    if @plugins.dispatch(:allow_password_recovery).include?(false)
      redirect_back_or_default(controller: "home")
      session[:notice] = _("This environment doesn't allow password recovery.")
    end

    @change_password = ChangePassword.new

    if request.post?
      begin
        return false unless verify_captcha(:forgot_password, @change_password, nil, environment)

        requestors = fetch_requestors(params[:value])
        raise ActiveRecord::RecordNotFound if requestors.blank? || params[:value].blank?

        requestors.each do |requestor|
          ChangePassword.create!(requestor: requestor)
        end
        render action: "password_recovery_sent"
      rescue ActiveRecord::RecordNotFound
        if params[:value].blank?
          @change_password.errors[:base] << _("Can not recover user password with blank value.")
        else
          @change_password.errors[:base] << _('Could not find any user with %s equal to "%s".').html_safe % [fields_label, params[:value]]
        end
      rescue ActiveRecord::RecordInvalid
        @change_password.errors[:base] << _("Could not perform password recovery for the user.")
      end
    end
  end

  # The user has a code for a ChangePassword request object.
  #
  # Posts back.
  def new_password
    @change_password = ChangePassword.from_code(params[:code]).first

    unless @change_password
      render action: "invalid_change_password_code", status: 403
      return
    end

    if request.post?
      begin
        @change_password.update!(params[:change_password])
        @change_password.finish
        render action: "new_password_ok"
      rescue ActiveRecord::RecordInvalid => e
        nil # just render new_password
      end
    end
  end

  def activation_question
    @enterprise = load_enterprise
    unless @enterprise
      render action: "invalid_enterprise_code"
      return
    end
    if @enterprise.enabled
      render action: "already_activated"
      return
    end

    @question = @enterprise.question
    if !@question || @enterprise.blocked?
      render action: "blocked"
      return
    end
  end

  def accept_terms
    @enterprise = load_enterprise
    @question = @enterprise.question
    if !@question || @enterprise.blocked?
      render action: "blocked"
      return
    end

    check_answer
    @terms_of_enterprise_use = environment.terms_of_enterprise_use
  end

  def activate_enterprise
    @terms_of_use = environment.terms_of_use
    @enterprise = load_enterprise
    @question = @enterprise.question
    return unless check_answer
    return unless check_acceptance_of_terms

    activation = load_enterprise_activation
    if activation && user
      activation.requestor = user
      activation.finish
      redirect_to action: "welcome", enterprise: @enterprise.id
    end
  end

  def welcome
    @enterprise = Enterprise.find(params[:enterprise])
    unless @enterprise.enabled? && logged_in?
      redirect_to action: "index"
    end
  end

  def check_valid_name
    @identifier = params[:identifier]
    valid = Person.is_available?(@identifier, environment)

    if valid
      @status = _("This login name is available")
      @status_class = "validated"
    elsif !@identifier.empty?
      @suggested_usernames = suggestion_based_on_username(@identifier)
      @status = _("This login name is unavailable")
      @status_class = "invalid"
    else
      @status_class = "invalid"
      @status = _("This field can't be blank")
    end
    render partial: "identifier_status"
  end

  def check_email
    if User.find_by(email: params[:address], environment_id: environment.id).nil?
      @status = _("This e-mail address is available")
      @status_class = "validated"
    else
      @status = _("This e-mail address is taken")
      @status_class = "invalid"
    end
    render partial: "email_status"
  end

  def user_data
    user_data =
      if logged_in?
        current_user.data_hash(gravatar_default)
      else
        {}
      end

    if session[:notice]
      user_data["notice"] = session[:notice]
      session[:notice] = nil # consume the notice
    end

    @plugins.each do |plugin|
      user_data_extras = plugin.user_data_extras
      user_data_extras = instance_exec(&user_data_extras) if user_data_extras.kind_of?(Proc)
      user_data.merge!(user_data_extras)
    end

    render plain: user_data.to_json, layout: false, content_type: "application/javascript"
  end

  def search_cities
    if request.xhr? && params[:state_name] && params[:city_name]
      render json: MapsHelper.search_city(params[:city_name], params[:state_name])
    else
      render json: [].to_json
    end
  end

  def search_state
    if request.xhr? && params[:state_name]
      render json: MapsHelper.search_state(params[:state_name])
    else
      render json: [].to_json
    end
  end

  protected

    def redirect?
      !@cannot_redirect
    end

    def no_redirect
      @cannot_redirect = true
    end

    def check_answer
      unless answer_correct
        @enterprise.block
        render action: "blocked"
        return
      end
      true
    end

    def check_acceptance_of_terms
      if params[:terms_accepted].to_s == "false"
        redirect_to action: "index"
        return
      end
      true
    end

    def load_enterprise_activation
      @enterprise_activation ||= EnterpriseActivation.from_code(params[:enterprise_code]).first
    end

    def load_enterprise
      activation = load_enterprise_activation
      if activation.nil?
        nil
      else
        activation.enterprise
      end
    end

    def answer_correct
      return true unless params[:enterprise_code]

      enterprise = load_enterprise
      return false unless enterprise.question
      return false if enterprise.enabled

      params[:answer] == enterprise.send(enterprise.question).to_s
    end

    def go_to_initial_page
      if params[:return_to]
        redirect_to url_for(params[:return_to])
      elsif environment.enabled?("allow_change_of_redirection_after_login")
        check_redirection_options(user, user.preferred_login_redirection, user.admin_url)
      else
        if environment == current_user.environment
          check_redirection_options(user, environment.redirection_after_login, user.admin_url)
        else
          redirect_back_or_default(controller: "home")
        end
      end
    end

    def go_to_signup_initial_page
      check_redirection_options user, user.environment.redirection_after_signup, user.url, signup: true
    end

    def redirect_if_logged_in
      if logged_in?
        go_to_initial_page
      end
    end

    def plugins_alternative_authentication
      user = nil
      @plugins.each do |plugin|
        user = plugin.alternative_authentication
        break unless user.nil?
      end
      user
    end

  protected

    def check_redirection_options(user, condition, default, options = {})
      if options[:signup] && (target = session.delete(:after_signup_redirect_to))
        redirect_to target
      else
        case condition
        when "keep_on_same_page"
          redirect_back_or_default(user.admin_url)
        when "site_homepage"
          redirect_to controller: :home
        when "domain_root"
          redirect_to "/"
        when "user_profile_page"
          redirect_to user.public_profile_url
        when "user_homepage"
          redirect_to user.url
        when "user_control_panel"
          redirect_to user.admin_url
        when "welcome_page"
          redirect_to controller: :home, action: :welcome, template_id: (user.template && user.template.id)
        when "custom_url"
          if (url = user.custom_url_redirection).present? then redirect_to url else redirect_back_or_default default end
        else
          redirect_back_or_default(default)
        end
      end
    end

    def check_redirection
      unless params[:redirection].blank?
        session[:return_to] = @user.return_to
        @user.update(return_to: nil)
      end
    end

    def check_join_in_community(user)
      profile_to_join = session[:join]
      unless profile_to_join.blank?
        environment.profiles.find_by(identifier: profile_to_join).add_member(user.person)
        session.delete(:join)
      end
    end

    def check_activation_token
      redirect_to action: :login unless params[:activation_token].present?
    end
end