<commit_before>class JoinController < ApplicationController


  # When the user is not yet signed up, we get their project information from
  # them first. We store all this in a "guest" user, and then at the end, we
  # sign the guest user in, and update the information with their real info. The
  # reason we go this way, instead of storing the information in a session, is
  # that it works just fine this way, and changing it is a hassle. In
  # particular, if we change it, we have to find a way for the front/back end to
  # pass information around, which is a bit of a refactoring away from working
  # well.
  def all
    @url = Github.authorization_url join_url
    @user = current_or_guest_user

    initialize_state
    @step, @substep = step_for_state
    do_state_action
  end

  def dynamic
    fetcher = session[:fetcher]
    if fetcher then
      ready = Backend.worker_done? fetcher
      if ready then
        @result = Backend.wait_for_worker fetcher
        session[:fetcher] = nil
      end
    end

    # TODO I used to move this along using the session[:next] thing

    if ready

      increment_state
      do_state_action

      step, substep = step_for_state
      body = render_to_string :partial => "body#{step}_#{substep}"
    end

    keep_polling = (not session[:stop])
    session[:stop] = false

    packet = {
      :step => step,
      :substep => substep,
      :ready => ready,
      :keep_polling => keep_polling,
      :body => body,
    }.to_json

    render :json => packet
  end

  def add_projects
    projects = []
    params.each do |key, value|
      if value == "add_project"
        projects.push key
      end
    end

    # TECHNICAL_DEBT (minor for now): a better way to model github is to
    # constantly sync projects and users into special GH models, and look them
    # up directly.

    # Add all projects the user has access to.
    projects.each do |user_repo_pair|
      username, projectname = user_repo_pair.split "/"
      gh_url = Backend.blocking_worker "circle.backend.github-url/canonical-url", username, projectname

      project = Project.where(:vcs_url => gh_url).first

      allowed_urls = session[:allowed_urls] || []
      allowed = allowed_urls.any? { |u| u == gh_url }

      next if not allowed

      if not project
        project = Project.create! :name => projectname, :vcs_url => gh_url
      end

      project.users << current_or_guest_user
      project.save!

      Github.add_deploy_key current_or_guest_user, project, username, projectname
      Github.add_commit_hook username, projectname, current_or_guest_user
    end

    session[:allowed_urls] = nil

    increment_state
    do_state_action
    if current_or_guest_user.sign_in_count > 0
      redirect_to root_url
    else
      redirect_to join_url
    end
  end


  def increment_state
    session[:state] =
      case session[:state]
      when :start
        session[:stop] = true
        :start
      when :authorizing
        :fetching_projects
      when :fetching_projects
        session[:stop] = true
        :list_projects
      when :list_projects
        :signup
      when :signup
        session[:stop] = true
        :signup
      end
  end


  def do_state_action
    code = params[:code]
    access_token = current_or_guest_user.github_access_token

    # Start whatever job the state requires
    case session[:state]
    when :start
      # TODO: put this into the logs in a more structured way. But for now, we
      # have this so that we can compare it to people who follow through.
      logger.info "Started signup from #{params[:email]}"

      # Some stats
      current_or_guest_user.signup_channel = params["source"]
      current_or_guest_user.signup_referer = request.env["HTTP_REFERER"]

      session[:stop] = true


    when :authorizing
      session[:fetcher] = Github.fetch_access_token current_or_guest_user, code

    when :fetching_projects
      session[:fetcher] = Github.all_repos current_or_guest_user
      Backend.fire_worker "circle.workers.github/add-user-details", current_or_guest_user.id.to_s

    when :list_projects
      session[:allowed_urls] = @result.map { |p| p[:html_url] }

    end


    # # TODO: start a worker which gets a list of builds
    # # TODO: in the background, check them out, infer them, and stream the build to the user.
    # # TODO: this means not waiting five minutes for the build to start!
  end


  def initialize_state
    code = params[:code]
    access_token = current_or_guest_user.github_access_token

    session[:state] =
      if current_or_guest_user.sign_in_count > 0
        :fetching_projects
      elsif code.nil? and access_token.nil?
        :start<commit_msg>Don't keep polling at :signup state.<commit_after>class JoinController < ApplicationController


  # When the user is not yet signed up, we get their project information from
  # them first. We store all this in a "guest" user, and then at the end, we
  # sign the guest user in, and update the information with their real info. The
  # reason we go this way, instead of storing the information in a session, is
  # that it works just fine this way, and changing it is a hassle. In
  # particular, if we change it, we have to find a way for the front/back end to
  # pass information around, which is a bit of a refactoring away from working
  # well.
  def all
    @url = Github.authorization_url join_url
    @user = current_or_guest_user

    initialize_state
    @step, @substep = step_for_state
    do_state_action
  end

  def dynamic
    fetcher = session[:fetcher]
    if fetcher then
      ready = Backend.worker_done? fetcher
      if ready then
        @result = Backend.wait_for_worker fetcher
        session[:fetcher] = nil
      end
    end

    # TODO I used to move this along using the session[:next] thing

    if ready

      increment_state
      do_state_action

      step, substep = step_for_state
      body = render_to_string :partial => "body#{step}_#{substep}"
    end

    packet = {
      :step => step,
      :substep => substep,
      :ready => ready,
      :keep_polling => keep_polling?,
      :body => body,
    }.to_json

    render :json => packet
  end

  def add_projects
    projects = []
    params.each do |key, value|
      if value == "add_project"
        projects.push key
      end
    end

    # TECHNICAL_DEBT (minor for now): a better way to model github is to
    # constantly sync projects and users into special GH models, and look them
    # up directly.

    # Add all projects the user has access to.
    projects.each do |user_repo_pair|
      username, projectname = user_repo_pair.split "/"
      gh_url = Backend.blocking_worker "circle.backend.github-url/canonical-url", username, projectname

      project = Project.where(:vcs_url => gh_url).first

      allowed_urls = session[:allowed_urls] || []
      allowed = allowed_urls.any? { |u| u == gh_url }

      next if not allowed

      if not project
        project = Project.create! :name => projectname, :vcs_url => gh_url
      end

      project.users << current_or_guest_user
      project.save!

      Github.add_deploy_key current_or_guest_user, project, username, projectname
      Github.add_commit_hook username, projectname, current_or_guest_user
    end

    session[:allowed_urls] = nil

    increment_state
    do_state_action
    if current_or_guest_user.sign_in_count > 0
      redirect_to root_url
    else
      redirect_to join_url
    end
  end

  def keep_polling?
    case session[:state]
    when :start
      false
    when :authorizing
      true
    when :fetching_projects
      true
    when :list_projects
      false
    when :signup
      false
    end
  end

  def increment_state
    session[:state] =
      case session[:state]
      when :start
        :start
      when :authorizing
        :fetching_projects
      when :fetching_projects
        :list_projects
      when :list_projects
        :signup
      when :signup
        :signup
      end
  end


  def do_state_action
    code = params[:code]
    access_token = current_or_guest_user.github_access_token

    # Start whatever job the state requires
    case session[:state]
    when :start
      # TODO: put this into the logs in a more structured way. But for now, we
      # have this so that we can compare it to people who follow through.
      logger.info "Started signup from #{params[:email]}"

      # Some stats
      current_or_guest_user.signup_channel = params["source"]
      current_or_guest_user.signup_referer = request.env["HTTP_REFERER"]



    when :authorizing
      session[:fetcher] = Github.fetch_access_token current_or_guest_user, code

    when :fetching_projects
      session[:fetcher] = Github.all_repos current_or_guest_user
      Backend.fire_worker "circle.workers.github/add-user-details", current_or_guest_user.id.to_s

    when :list_projects
      session[:allowed_urls] = @result.map { |p| p[:html_url] }

    end


    # # TODO: start a worker which gets a list of builds
    # # TODO: in the background, check them out, infer them, and stream the build to the user.
    # # TODO: this means not waiting five minutes for the build to start!
  end


  def initialize_state
    code = params[:code]
    access_token = current_or_guest_user.github_access_token

    session[:state] =
      if current_or_guest_user.sign_in_count > 0
        :fetching_projects
      elsif code.nil? and access_token.nil?
        :start
{'fraction_non_alphanumeric': 0.07148891235480465, 'fraction_numerical': 0.00042238648363252375, 'mean_word_length': 2.728740157480315, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5088798', 'n_tokens_mistral': 2911, 'n_tokens_neox': 2819, 'n_words': 918}