mirror of
				https://github.com/scinote-eln/scinote-web.git
				synced 2025-11-04 03:59:08 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			294 lines
		
	
	
	
		
			9.1 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			294 lines
		
	
	
	
		
			9.1 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
class Users::RegistrationsController < Devise::RegistrationsController
 | 
						|
  prepend_before_action :check_captcha, only: [:create]
 | 
						|
  before_action :registration_enabled?,
 | 
						|
                only: %i(new create new_with_provider create_with_provider)
 | 
						|
  before_action :sign_up_with_provider_enabled?,
 | 
						|
                only: %i(new_with_provider create_with_provider)
 | 
						|
  layout :layout
 | 
						|
 | 
						|
  def avatar
 | 
						|
    user = User.find_by_id(params[:id]) || current_user
 | 
						|
    style = params[:style] || :icon_small
 | 
						|
    redirect_to user.avatar_url(style)
 | 
						|
  end
 | 
						|
 | 
						|
  def update_resource(resource, params)
 | 
						|
    @user_avatar_url = avatar_path(current_user, :thumb)
 | 
						|
 | 
						|
    if params.include? :change_password
 | 
						|
      # Special handling if changing password
 | 
						|
      params.delete(:change_password)
 | 
						|
      if resource.valid_password?(params[:current_password]) &&
 | 
						|
         params.include?(:password) &&
 | 
						|
         params.include?(:password_confirmation) &&
 | 
						|
         params[:password].blank?
 | 
						|
        # If new password is blank and we're in process of changing
 | 
						|
        # password, add error to the resource and return false
 | 
						|
        resource.errors.add(:password, :blank)
 | 
						|
        false
 | 
						|
      else
 | 
						|
        resource.update_with_password(params)
 | 
						|
      end
 | 
						|
    elsif params.include? :change_avatar
 | 
						|
      params.delete(:change_avatar)
 | 
						|
      if !params.include?(:avatar) || (params[:avatar].length > Constants::AVATAR_MAX_SIZE_MB.megabytes * 2)
 | 
						|
        resource.errors.add(:avatar, :blank)
 | 
						|
        false
 | 
						|
      else
 | 
						|
        temp_file = Tempfile.new('avatar', Rails.root.join('tmp'))
 | 
						|
        begin
 | 
						|
          check_extension = params[:avatar].split(';')[0].split('/')[1]
 | 
						|
          temp_file.binmode
 | 
						|
          temp_file.write(Base64.decode64(params[:avatar].split(',')[1]))
 | 
						|
          temp_file.rewind
 | 
						|
          resource.avatar.attach(io: temp_file, filename: "avatar.#{check_extension}")
 | 
						|
        ensure
 | 
						|
          temp_file.close
 | 
						|
          temp_file.unlink
 | 
						|
        end
 | 
						|
        params.delete(:avatar)
 | 
						|
        resource.update_without_password(params)
 | 
						|
      end
 | 
						|
    elsif params.include?(:email) || params.include?(:password)
 | 
						|
      # For changing email or password, validate current_password
 | 
						|
      resource.update_with_password(params)
 | 
						|
    else
 | 
						|
      # For changing some attributes, no current_password validation
 | 
						|
      # is required
 | 
						|
      resource.update_without_password(params)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  # Override default registrations_controller.rb implementation
 | 
						|
  # to support JSON
 | 
						|
  def update
 | 
						|
    change_password = account_update_params.include? :change_password
 | 
						|
    respond_to do |format|
 | 
						|
      self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
 | 
						|
      prev_unconfirmed_email = resource.unconfirmed_email if resource.respond_to?(:unconfirmed_email)
 | 
						|
 | 
						|
      resource_updated = update_resource(resource, account_update_params)
 | 
						|
 | 
						|
      yield resource if block_given?
 | 
						|
      if resource_updated
 | 
						|
        # Set "needs confirmation" flash if neccesary
 | 
						|
        if is_flashing_format? || account_update_params['change_avatar']
 | 
						|
          flash_key = update_needs_confirmation?(resource, prev_unconfirmed_email) ?
 | 
						|
            :update_needs_confirmation : :updated
 | 
						|
          set_flash_message :notice, flash_key
 | 
						|
        end
 | 
						|
 | 
						|
        # Set "password successfully updated" flash if neccesary
 | 
						|
        if change_password
 | 
						|
          set_flash_message :notice, :password_changed
 | 
						|
        end
 | 
						|
 | 
						|
        format.html {
 | 
						|
          sign_in resource_name, resource, bypass: true
 | 
						|
          respond_with resource, location: edit_user_registration_path
 | 
						|
        }
 | 
						|
        format.json {
 | 
						|
          flash.keep
 | 
						|
          sign_in resource_name, resource, bypass: true
 | 
						|
          render json: {}
 | 
						|
        }
 | 
						|
      else
 | 
						|
        clean_up_passwords resource
 | 
						|
        format.html {
 | 
						|
          respond_with resource, location: edit_user_registration_path
 | 
						|
        }
 | 
						|
        format.json {
 | 
						|
          render json: resource.errors, status: :bad_request
 | 
						|
        }
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def new; end
 | 
						|
 | 
						|
  def create
 | 
						|
    build_resource(sign_up_params)
 | 
						|
    valid_resource = resource.valid?
 | 
						|
    # ugly checking if new team on sign up is enabled :(
 | 
						|
    if Rails.configuration.x.new_team_on_signup
 | 
						|
      # Create new team for the new user
 | 
						|
      @team = Team.new
 | 
						|
      @team.name = params[:team][:name]
 | 
						|
      valid_team = @team.valid?
 | 
						|
 | 
						|
      if valid_team && valid_resource
 | 
						|
        # this must be called after @team variable is defined. Otherwise this
 | 
						|
        # variable won't be accessable in view.
 | 
						|
        super do |resource|
 | 
						|
          # Set the confirmed_at == created_at IF not using email confirmations
 | 
						|
          unless Rails.configuration.x.enable_email_confirmations
 | 
						|
            resource.update(confirmed_at: resource.created_at)
 | 
						|
          end
 | 
						|
 | 
						|
          if resource.valid? && resource.persisted?
 | 
						|
            @team.created_by = resource # set created_by for oraganization
 | 
						|
            @team.save
 | 
						|
 | 
						|
            # Add this user to the team as owner
 | 
						|
            UserTeam.create(user: resource, team: @team, role: :admin)
 | 
						|
 | 
						|
            # set current team to new user
 | 
						|
            resource.current_team_id = @team.id
 | 
						|
            resource.save
 | 
						|
          end
 | 
						|
        end
 | 
						|
      else
 | 
						|
        render :new
 | 
						|
      end
 | 
						|
    elsif valid_resource
 | 
						|
      super do |resource|
 | 
						|
        # Set the confirmed_at == created_at IF not using email confirmations
 | 
						|
        unless Rails.configuration.x.enable_email_confirmations
 | 
						|
          resource.update(confirmed_at: resource.created_at)
 | 
						|
          resource.save
 | 
						|
        end
 | 
						|
      end
 | 
						|
    else
 | 
						|
      render :new
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def new_with_provider; end
 | 
						|
 | 
						|
  def create_with_provider
 | 
						|
    @user = User.find_by_id(user_provider_params['user'])
 | 
						|
    # Create new team for the new user
 | 
						|
    @team = Team.new(team_provider_params)
 | 
						|
 | 
						|
    if @team.valid? && @user && Rails.configuration.x.new_team_on_signup
 | 
						|
      # Set the confirmed_at == created_at IF not using email confirmations
 | 
						|
      unless Rails.configuration.x.enable_email_confirmations
 | 
						|
        @user.update!(confirmed_at: @user.created_at)
 | 
						|
      end
 | 
						|
 | 
						|
      @team.created_by = @user # set created_by for team
 | 
						|
      @team.save!
 | 
						|
 | 
						|
      # Add this user to the team as owner
 | 
						|
      UserTeam.create(user: @user, team: @team, role: :admin)
 | 
						|
 | 
						|
      # set current team to new user
 | 
						|
      @user.current_team_id = @team.id
 | 
						|
      @user.save!
 | 
						|
 | 
						|
      sign_in_and_redirect @user
 | 
						|
    else
 | 
						|
      render :new_with_provider
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def two_factor_enable
 | 
						|
    if current_user.valid_otp?(params[:submit_code])
 | 
						|
      recovery_codes = current_user.enable_2fa!
 | 
						|
      render json: { recovery_codes: recovery_codes }
 | 
						|
    else
 | 
						|
      render json: { error: t('users.registrations.edit.2fa_errors.wrong_submit_code') }, status: :unprocessable_entity
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def two_factor_disable
 | 
						|
    if current_user.valid_password?(params[:password])
 | 
						|
      current_user.disable_2fa!
 | 
						|
      redirect_to edit_user_registration_path
 | 
						|
    else
 | 
						|
      render json: { error: t('users.registrations.edit.2fa_errors.wrong_password') }, status: :forbidden
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def two_factor_qr_code
 | 
						|
    current_user.assign_2fa_token!
 | 
						|
    qr_code_url = ROTP::TOTP.new(current_user.otp_secret, issuer: 'SciNote').provisioning_uri(current_user.email)
 | 
						|
    qr_code = RQRCode::QRCode.new(qr_code_url)
 | 
						|
    render json: { qr_code: qr_code.as_svg(module_size: 4) }
 | 
						|
  end
 | 
						|
 | 
						|
  protected
 | 
						|
 | 
						|
  # Called upon creating User (before .save). Permits parameters and extracts
 | 
						|
  # initials from :full_name (takes at most 4 chars). If :full_name is empty, it
 | 
						|
  # uses "PLCH" as a placeholder (user won't get error complaining about
 | 
						|
  # initials being empty.
 | 
						|
  def sign_up_params
 | 
						|
    tmp = params.require(:user).permit(:full_name, :initials, :email, :password, :password_confirmation)
 | 
						|
    initials = tmp[:full_name].titleize.scan(/[A-Z]+/).join()
 | 
						|
    initials = if initials.strip.blank?
 | 
						|
                 'PLCH'
 | 
						|
               else
 | 
						|
                 initials[0..Constants::USER_INITIALS_MAX_LENGTH]
 | 
						|
               end
 | 
						|
    tmp.merge(:initials => initials)
 | 
						|
  end
 | 
						|
 | 
						|
  def team_provider_params
 | 
						|
    params.require(:team).permit(:name)
 | 
						|
  end
 | 
						|
 | 
						|
  def user_provider_params
 | 
						|
    params.permit(:user)
 | 
						|
  end
 | 
						|
 | 
						|
  def account_update_params
 | 
						|
    params.require(:user).permit(
 | 
						|
      :full_name,
 | 
						|
      :initials,
 | 
						|
      :avatar,
 | 
						|
      :email,
 | 
						|
      :password,
 | 
						|
      :password_confirmation,
 | 
						|
      :current_password,
 | 
						|
      :change_password,
 | 
						|
      :change_avatar,
 | 
						|
      :external_id
 | 
						|
    )
 | 
						|
  end
 | 
						|
 | 
						|
  def avatar_params
 | 
						|
    params.permit(
 | 
						|
      :file
 | 
						|
    )
 | 
						|
  end
 | 
						|
 | 
						|
  private
 | 
						|
 | 
						|
  def layout
 | 
						|
    'fluid' if action_name == 'edit'
 | 
						|
  end
 | 
						|
 | 
						|
  def check_captcha
 | 
						|
    if Rails.configuration.x.enable_recaptcha
 | 
						|
      unless verify_recaptcha
 | 
						|
        # Construct new resource before rendering :new
 | 
						|
        self.resource = resource_class.new sign_up_params
 | 
						|
 | 
						|
        # Also validate team
 | 
						|
        @team = Team.new(name: params[:team][:name])
 | 
						|
        @team.valid?
 | 
						|
 | 
						|
        respond_with_navigational(resource) { render :new }
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def registration_enabled?
 | 
						|
    render_403 unless Rails.configuration.x.enable_user_registration
 | 
						|
  end
 | 
						|
 | 
						|
  def sign_up_with_provider_enabled?
 | 
						|
    render_403 unless Rails.configuration.x.linkedin_signin_enabled
 | 
						|
  end
 | 
						|
 | 
						|
  # Redirect to login page after signing up
 | 
						|
  def after_sign_up_path_for(resource)
 | 
						|
    new_user_session_path
 | 
						|
  end
 | 
						|
 | 
						|
  # Redirect to login page after signing up
 | 
						|
  def after_inactive_sign_up_path_for(resource)
 | 
						|
    new_user_session_path
 | 
						|
  end
 | 
						|
end
 |