# frozen_string_literal: true require 'google/apis/sheets_v4' module SpreadsheetBackends class GoogleSheets # Hash to translate an index to a A1 notation. e.g. 1 => 'B', 27 => 'AA' COLUMN_INDEX_TO_LETTER = Hash.new { |hash, key| hash[key] = hash[key - 1].next }.merge({ 0 => 'A' }) attr_accessor :form, :user def initialize(form) @form = form @user = form.user end def url "https://docs.google.com/spreadsheets/d/#{form.google_spreadsheet_id}/edit" if form.google_spreadsheet_id.present? end def append(data) data = data.with_indifferent_access check_spreadsheed_headers!(data) values = headers.map { |key| data[key] } range = "A1:A#{COLUMN_INDEX_TO_LETTER[values.length]}1" value_range = Google::Apis::SheetsV4::ValueRange.new(values: [values], major_dimension: 'ROWS') result = spreadsheet_service.append_spreadsheet_value(form.google_spreadsheet_id, range, value_range, value_input_option: 'USER_ENTERED') result.updates.updated_rows > 0 end def create sheets = Google::Apis::SheetsV4::SheetsService.new sheets.authorization = user.google_authorization create_object = Google::Apis::SheetsV4::Spreadsheet.new(properties: { title: form.title }) spreadsheet = sheets.create_spreadsheet(create_object) form.update(google_spreadsheet_id: spreadsheet.spreadsheet_id) end def headers @headers ||= begin values = spreadsheet_service.get_spreadsheet_values(form.google_spreadsheet_id, 'A1:An').values # if there are no headers yet, return an empty array if values values[0].map(&:strip) else [] end end end def spreadsheet_service @spreadsheet_service ||= Google::Apis::SheetsV4::SheetsService.new.tap do |s| s.authorization = user.google_authorization end end def check_spreadsheed_headers!(data) missing_headers = data.keys.map { |k| k.to_s.strip } - headers append_missing_headers(missing_headers) unless missing_headers.empty? end def append_missing_headers(missing_headers) start_column = COLUMN_INDEX_TO_LETTER[headers.length] end_column = COLUMN_INDEX_TO_LETTER[headers.length + missing_headers.length] range = "#{start_column}1:#{end_column}1" value_range = Google::Apis::SheetsV4::ValueRange.new(values: [missing_headers], major_dimension: 'ROWS') spreadsheet_service.update_spreadsheet_value(form.google_spreadsheet_id, range, value_range, value_input_option: 'USER_ENTERED') @headers = nil # reset header values to refresh memoization on next access end end end