<commit_before>module Api
  class ApiController < ActionController::Base
    attr_reader :iss
    attr_reader :token
    attr_reader :current_user

    before_action :load_token, except: %i(authenticate status)
    before_action :load_iss, except: %i(authenticate status)
    before_action :authenticate_request!, except: %i(authenticate status)

    rescue_from StandardError do
      render json: {}, status: :bad_request
    end

    rescue_from JWT::InvalidPayload, JWT::DecodeError do
      render json: { message: I18n.t('api.core.invalid_token') },
             status: :unauthorized
    end

    def initialize
      super
      @iss = nil
    end

    def status
      response = {}
      response[:message] = I18n.t('api.core.status_ok')
      response[:versions] = []
      Extends::API_VERSIONS.each do |ver|
        response[:versions] << { version: ver, baseUrl: "/api/#{ver}/" }
      end
      render json: response, status: :ok
    end

    def authenticate
      if auth_params[:grant_type] == 'password'
        user = User.find_by_email(auth_params[:email])
        raise StandardError unless user &&
                                   user.valid_password?(auth_params[:password])
        payload = { user_id: user.id }
        token = CoreJwt.encode(payload)
        render json: { token_type: 'bearer', access_token: token }
      else
        raise StandardError
      end
    end

    private

    def load_token
      @token =
        request.headers['Authorization'].scan(/Bearer (.*)$/).flatten.last
      raise StandardError unless @token
    end

    def authenticate_request!
      Extends::API_PLUGABLE_AUTH_METHODS.each do |auth_method|
        method(auth_method).call
        return true if current_user
      end
      # Check request header for proper auth token
      payload = CoreJwt.decode(token)
      @current_user = User.find_by_id(payload['user_id'])
      # Implement sliding sessions, i.e send new token in case of successful
      # authorization and when tokens TTL reached specific value (to avoid token
      # generation on each request)
      if CoreJwt.refresh_needed?(payload)
        new_token = CoreJwt.encode(user_id: @current_user.id)
        response.headers['X-Access-Token'] = new_token
      end
    rescue JWT::ExpiredSignature
      render json: { message: I18n.t('api.core.expired_token') },
             status: :unauthorized
    end

    def load_iss
      @iss = CoreJwt.read_iss(token)
      raise JWT::InvalidPayload unless @iss
    end

    def auth_params
      params.permit(:grant_type, :email, :password)
    end
  end
end<commit_msg>Improve error logging [GIOT-31]<commit_after>module Api
  class ApiController < ActionController::Base
    attr_reader :iss
    attr_reader :token
    attr_reader :current_user

    before_action :load_token, except: %i(authenticate status)
    before_action :load_iss, except: %i(authenticate status)
    before_action :authenticate_request!, except: %i(authenticate status)

    rescue_from StandardError do |e|
      logger.error e.message
      render json: {}, status: :bad_request
    end

    rescue_from JWT::InvalidPayload, JWT::DecodeError do |e|
      logger.error e.message
      render json: { message: I18n.t('api.core.invalid_token') },
             status: :unauthorized
    end

    def initialize
      super
      @iss = nil
    end

    def status
      response = {}
      response[:message] = I18n.t('api.core.status_ok')
      response[:versions] = []
      Extends::API_VERSIONS.each do |ver|
        response[:versions] << { version: ver, baseUrl: "/api/#{ver}/" }
      end
      render json: response, status: :ok
    end

    def authenticate
      if auth_params[:grant_type] == 'password'
        user = User.find_by_email(auth_params[:email])
        unless user && user.valid_password?(auth_params[:password])
          raise StandardError, 'Wrong user password'
        end
        payload = { user_id: user.id }
        token = CoreJwt.encode(payload)
        render json: { token_type: 'bearer', access_token: token }
      else
        raise StandardError, 'Wrong grant type in request'
      end
    end

    private

    def load_token
      if request.headers['Authorization']
        @token =
          request.headers['Authorization'].scan(/Bearer (.*)$/).flatten.last
      end
      raise StandardError, 'No token in the header' unless @token
    end

    def authenticate_request!
      Extends::API_PLUGABLE_AUTH_METHODS.each do |auth_method|
        method(auth_method).call
        return true if current_user
      end
      # Check request header for proper auth token
      payload = CoreJwt.decode(token)
      @current_user = User.find_by_id(payload['user_id'])
      # Implement sliding sessions, i.e send new token in case of successful
      # authorization and when tokens TTL reached specific value (to avoid token
      # generation on each request)
      if CoreJwt.refresh_needed?(payload)
        new_token = CoreJwt.encode(user_id: @current_user.id)
        response.headers['X-Access-Token'] = new_token
      end
    rescue JWT::ExpiredSignature
      render json: { message: I18n.t('api.core.expired_token') },
             status: :unauthorized
    end

    def load_iss
      @iss = CoreJwt.read_iss(token)
      raise JWT::InvalidPayload, 'Wrong ISS in the token' unless @iss
    end

    def auth_params
      params.permit(:grant_type, :email, :password)
    end
  end
end
{'fraction_non_alphanumeric': 0.094294624839479, 'fraction_numerical': 0.002568336085121996, 'mean_word_length': 2.696271186440678, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '393948', 'n_tokens_mistral': 1630, 'n_tokens_neox': 1592, 'n_words': 416}