ashirahattia/cs169-pgm

View on GitHub
app/controllers/google_controller.rb

Summary

Maintainability
A
25 mins
Test Coverage
require 'google/apis/sheets_v4'
require 'googleauth'
require 'googleauth/stores/file_token_store'

require 'fileutils'

class GoogleController < ApplicationController
  include MatchesHelper
  include ApplicationHelper
  include GoogleHelper

  before_filter :check_logged_in

  @@SETTINGS = Setting.first

  def projects_groups_fetch
    return (check_authorization && fetch_project_data) ? fetch_group_data : nil
  end

  def write_matches
    return check_authorization ? write_all_matches : nil
  end

  def fetch_matches
    return check_authorization ? update_matches_sheet : nil
  end

  def save_preferences
    if check_authorization
      update_settings
      @@SETTINGS = Setting.first
      redirect_to google_fetch_path
    end
  end

  def index
  end

  def settings
  end

  #### CS169-PGM GOOGLE METHODS BEGIN ####

  def fetch_project_data
    response = fetch_data(@@SETTINGS.project_tab)
    unless response.nil?
      adjust_projects response
      return true
    end
    false
  end

  def adjust_projects(response)
    Project.destroy_all
    delete_matches(response)
    create_projects(response)
  end

  def create_projects(response)
    response.values.each do |row|
      row[@@SETTINGS.project_id_col.to_i].nil? ? (return) : Project.create(:id => row[@@SETTINGS.project_id_col.to_i],
                     :project_name => row[@@SETTINGS.project_name_col.to_i])
    end
  end

  #Fetches the data from the google sheet
  def fetch_group_data
    response = fetch_data(@@SETTINGS.group_tab)
    unless response.nil?
      adjust_groups response
    end
  end

  # Takes the google sheet response and generates all the groups from it
  def adjust_groups(response)
    Group.destroy_all
    delete_matches(response)
    create_groups(response)
    redirect_to root_path
  end

  def create_groups(response)
    response.values.each do |row|
      if row[@@SETTINGS.group_id_col.to_i].nil?
        return
      end
      preferences = []
      preference_rows = row
      preference_rows.each do |preference|
        id = (/\d+/.match(preference))
        if !id.nil?
          preferences.push(id[0])
        else
          preferences.push([])
        end
      end
      Group.create(:id => row[@@SETTINGS.group_id_col.to_i], :username => row[@@SETTINGS.group_username_col.to_i],
                   :first_choice => preferences[@@SETTINGS.group_preference_1.to_i],
                   :second_choice => preferences[@@SETTINGS.group_preference_2.to_i],
                   :third_choice => preferences[@@SETTINGS.group_preference_3.to_i],
                   :fourth_choice => preferences[@@SETTINGS.group_preference_4.to_i],
                   :fifth_choice => preferences[@@SETTINGS.group_preference_5.to_i],
                   :sixth_choice => preferences[@@SETTINGS.group_preference_6.to_i],
                   :seventh_choice => preferences[@@SETTINGS.group_preference_7.to_i])
    end
  end

  def update_matches_sheet
    response = fetch_data(@@SETTINGS.matches_tab)
    unless response.nil?
      response = delete_matches(response)
      response.values.each do |row|
        if row[0] != 'None'
          Match.create(:group_id => row[0], :project_id => row[1])
        end
      end
      flash[:notice] = 'Matches Fetched and '
      write_all_matches
    end
  end

  def write_all_matches
    temp_matches = Match.all.sort_by { |some_match| (some_match.group.id.to_i) }
    match_values = [['Group ID', 'Project ID', 'Project Name']]
    temp_matches.each do |match|
      match_values.push([match.group.id, match.project.id, match.project.project_name])
    end
    find_unmatched_projects.each do |project|
      match_values.push(['None', project.id, project.project_name])
    end
    begin
      service_authorize.clear_values(@@SETTINGS.spreadsheet_id, @@SETTINGS.matches_tab)
      values = Google::Apis::SheetsV4::ValueRange.new({:values => match_values, :major_dimension => 'ROWS'})
      service_authorize.update_spreadsheet_value(@@SETTINGS.spreadsheet_id, @@SETTINGS.matches_tab, values,
                                                 value_input_option:'USER_ENTERED')
      flash[:notice] = flash[:notice] ? flash[:notice] + 'Matches Re-Alphabetized and Written.' : 'Matches Written.'
      redirect_to google_fetch_path
    rescue Signet::AuthorizationError, Google::Apis::AuthorizationError
      authorize true
      return
    end
  end

  #### GOOGLE METHODS BEGIN ####

  OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'
  APPLICATION_NAME = 'CS169'
  CLIENT_SECRETS_PATH = 'client_secret.json'
  CREDENTIALS_PATH = File.join(Dir.home, '.credentials',
                               "sheets.googleapis.com-ruby-quickstart.yaml")
  SCOPE = Google::Apis::SheetsV4::AUTH_SPREADSHEETS

  def complete_authorization
    FileUtils.mkdir_p(File.dirname(CREDENTIALS_PATH))

    client_id = Google::Auth::ClientId.from_file(CLIENT_SECRETS_PATH)
    token_store = Google::Auth::Stores::FileTokenStore.new(file: CREDENTIALS_PATH)
    authorizer = Google::Auth::UserAuthorizer.new(
        client_id, SCOPE, token_store)
    user_id = 'default'

    begin
      authorizer.get_and_store_credentials_from_code(user_id: user_id, code: params[:code], base_url: OOB_URI)
      session[:is_authorized] = true
    rescue Signet::AuthorizationError
      flash[:notice] = 'Error, invalid code. Try again'
    end

    redirect_to google_fetch_path
  end

  def check_authorization
    return authorize(false)
  end

  ##
  # Ensure valid credentials, either by restoring from the saved credentials
  # files or intitiating an OAuth2 authorization. If authorization is required,
  # the user's default browser will be launched to approve the request.
  #
  # @return [Google::Auth::UserRefreshCredentials] OAuth2 credentials
  def authorize(force_reload)
    FileUtils.mkdir_p(File.dirname(CREDENTIALS_PATH))

    client_id = Google::Auth::ClientId.from_file(CLIENT_SECRETS_PATH)
    token_store = Google::Auth::Stores::FileTokenStore.new(file: CREDENTIALS_PATH)
    authorizer = Google::Auth::UserAuthorizer.new(
        client_id, SCOPE, token_store)
    user_id = 'default'
    credentials = authorizer.get_credentials(user_id)
    if force_reload || credentials.nil?
      session[:is_authorized] = false
      redirect_to google_fetch_path
      return
    end
    credentials
  end

  def service_authorize
    service = Google::Apis::SheetsV4::SheetsService.new
    service.client_options.application_name = APPLICATION_NAME
    service.authorization = authorize false
    service
  end

  def fetch_data(range)
    begin
      response = service_authorize.get_spreadsheet_values(@@SETTINGS.spreadsheet_id, range)
    rescue Signet::AuthorizationError, Google::Apis::AuthorizationError
      authorize true
      return
    rescue Google::Apis::ClientError
      flash[:notice] = "Error fetching: #{range} in spreadsheet id: #{@@SETTINGS.spreadsheet_id}"
      redirect_to google_fetch_path
      return
    end
    response
  end

end