From b0614557bbd5e89c2507c4d64f935b6f90f51cad Mon Sep 17 00:00:00 2001 From: Peter Retzlaff Date: Sun, 5 Jan 2020 14:05:20 +0100 Subject: [PATCH 01/15] Add fields that were added in v5 of the API. --- lib/survey_gizmo/api/account_teams.rb | 9 +++++-- lib/survey_gizmo/api/campaign.rb | 21 +++++++++++---- lib/survey_gizmo/api/contact.rb | 37 +++++++++++++++++++++++++ lib/survey_gizmo/api/email_message.rb | 18 ++++++++++--- lib/survey_gizmo/api/option.rb | 3 +++ lib/survey_gizmo/api/page.rb | 7 ++++- lib/survey_gizmo/api/question.rb | 13 +++++++-- lib/survey_gizmo/api/response.rb | 39 +++++++++++++++++++++++---- lib/survey_gizmo/api/survey.rb | 6 +++-- 9 files changed, 133 insertions(+), 20 deletions(-) diff --git a/lib/survey_gizmo/api/account_teams.rb b/lib/survey_gizmo/api/account_teams.rb index 32e73c6..540cb7f 100644 --- a/lib/survey_gizmo/api/account_teams.rb +++ b/lib/survey_gizmo/api/account_teams.rb @@ -6,12 +6,17 @@ class AccountTeams include SurveyGizmo::Resource attribute :id, Integer - attribute :teamid, Integer attribute :teamname, String - attribute :color, String attribute :default_role, String attribute :status, String + # v4 fields + attribute :teamid, Integer + attribute :color, Integer + + # v5 fields + attribute :description, String + @route = '/accountteams' end end diff --git a/lib/survey_gizmo/api/campaign.rb b/lib/survey_gizmo/api/campaign.rb index b54072e..bfae9fd 100644 --- a/lib/survey_gizmo/api/campaign.rb +++ b/lib/survey_gizmo/api/campaign.rb @@ -5,24 +5,35 @@ class Campaign attribute :id, Integer attribute :name, String attribute :type, String - attribute :_type, String - attribute :subtype, String - attribute :_subtype, String - attribute :__subtype, String attribute :status, String attribute :uri, String attribute :SSL, Boolean - attribute :slug, String attribute :language, String attribute :close_message, String attribute :limit_responses, String attribute :tokenvariables, Array attribute :survey_id, Integer + + # v4 fields + attribute :_type, String + attribute :subtype, String + attribute :_subtype, String + attribute :__subtype, String + attribute :slug, String attribute :datecreated, DateTime attribute :datemodified, DateTime attribute :surveycampaign, Integer attribute :copy, Boolean + # v5 fields + attribute :invite_id, Integer + attribute :subtype, String + attribute :link_type, String + attribute :date_created, DateTime + attribute :date_modified, DateTime + attribute :link_open_date, DateTime + attribute :link_close_date, DateTime + @route = '/survey/:survey_id/surveycampaign' def contacts(conditions = {}) diff --git a/lib/survey_gizmo/api/contact.rb b/lib/survey_gizmo/api/contact.rb index 977c290..e547b3e 100644 --- a/lib/survey_gizmo/api/contact.rb +++ b/lib/survey_gizmo/api/contact.rb @@ -5,6 +5,8 @@ class Contact attribute :id, Integer attribute :survey_id, Integer attribute :campaign_id, Integer + + # v4 fields attribute :estatus, String attribute :esubscriberstatus, String attribute :semailaddress, String @@ -35,6 +37,41 @@ class Contact attribute :scustomfield9, String attribute :scustomfield10, String + # v5 fields + attribute :date_last_sent, DateTime + attribute :division, String + attribute :team, String + attribute :group, String + attribute :role, String + + attribute :status, String + attribute :subscriber_status, String + attribute :email_address, String + attribute :first_name, String + attribute :last_name, String + attribute :organization, String + attribute :department, String + attribute :business_phone, String + attribute :home_phone, String + attribute :fax_phone, String + attribute :mailing_address, String + attribute :mailing_address2, String + attribute :mailing_address_city, String + attribute :mailing_address_state, String + attribute :mailing_address_country, String + attribute :mailing_address_postal, String + attribute :title, String + attribute :url, String + attribute :customfield1, String + attribute :customfield2, String + attribute :customfield3, String + attribute :customfield4, String + attribute :customfield5, String + attribute :customfield6, String + attribute :customfield7, String + attribute :customfield8, String + attribute :customfield9, String + attribute :customfield10, String @route = '/survey/:survey_id/surveycampaign/:campaign_id/contact' end end diff --git a/lib/survey_gizmo/api/email_message.rb b/lib/survey_gizmo/api/email_message.rb index 27cb17c..214f9cb 100644 --- a/lib/survey_gizmo/api/email_message.rb +++ b/lib/survey_gizmo/api/email_message.rb @@ -6,19 +6,31 @@ class EmailMessage attribute :survey_id, Integer attribute :campaign_id, Integer attribute :invite_identity, Integer - attribute :_type, String - attribute :_subtype, String attribute :subject, String attribute :replies, String - attribute :messagetype, String attribute :medium, String attribute :status, String attribute :from, Hash attribute :body, Hash attribute :send, Boolean + + # v4 fields + attribute :_type, String + attribute :_subtype, String + attribute :messagetype, String attribute :datecreated, DateTime attribute :datemodified, DateTime + # v5 fields + attribute :type, String + attribute :subtype, String + attribute :message_type, String + attribute :footer, String + attribute :embed_question, Boolean + attribute :disable_styles, Boolean + attribute :date_created, DateTime + attribute :date_modified, DateTime + @route = '/survey/:survey_id/surveycampaign/:campaign_id/emailmessage' end end diff --git a/lib/survey_gizmo/api/option.rb b/lib/survey_gizmo/api/option.rb index 6d270fb..e1be5c6 100644 --- a/lib/survey_gizmo/api/option.rb +++ b/lib/survey_gizmo/api/option.rb @@ -10,6 +10,9 @@ class Option attribute :value, String attribute :properties, Hash + # v5 fields + attribute :title, String + @route = '/survey/:survey_id/surveypage/:page_id/surveyquestion/:question_id/surveyoption' end end diff --git a/lib/survey_gizmo/api/page.rb b/lib/survey_gizmo/api/page.rb index 304bb4b..da107db 100644 --- a/lib/survey_gizmo/api/page.rb +++ b/lib/survey_gizmo/api/page.rb @@ -8,10 +8,15 @@ class Page attribute :id, Integer attribute :description, String attribute :properties, Hash - attribute :after, Integer attribute :survey_id, Integer attribute :questions, Array[Question] + # v4 fields + attribute :after, Integer + + # v5 fields + attribute :title, String + @route = '/survey/:survey_id/surveypage' def survey diff --git a/lib/survey_gizmo/api/question.rb b/lib/survey_gizmo/api/question.rb index 1a2b137..fa92fe8 100644 --- a/lib/survey_gizmo/api/question.rb +++ b/lib/survey_gizmo/api/question.rb @@ -10,15 +10,24 @@ class Question attribute :description, String attribute :shortname, String attribute :properties, Hash - attribute :after, Integer attribute :options, Array[Option] attribute :survey_id, Integer attribute :page_id, Integer, default: 1 - attribute :sub_question_skus, Array attribute :parent_question_id, Integer + # v4 fields + attribute :after, Integer + attribute :sub_questions_skus, Array + alias_attribute :_subtype, :type + # v5 fields + attribute :base_type, String + attribute :varname, Array + attribute :has_showhide_deps, Boolean + attribute :comment, Boolean + attribute :sub_questions, Array[Question] + @route = { get: '/survey/:survey_id/surveyquestion/:id', create: '/survey/:survey_id/surveypage/:page_id/surveyquestion', diff --git a/lib/survey_gizmo/api/response.rb b/lib/survey_gizmo/api/response.rb index f4bc614..7bc0843 100644 --- a/lib/survey_gizmo/api/response.rb +++ b/lib/survey_gizmo/api/response.rb @@ -17,17 +17,42 @@ def self.submitted_since_filter(time) attribute :id, Integer attribute :survey_id, Integer attribute :contact_id, Integer - attribute :data, String attribute :status, String attribute :is_test_data, Boolean - attribute :sResponseComment, String - attribute :variable, Hash # READ-ONLY attribute :meta, Hash # READ-ONLY - attribute :shown, Hash # READ-ONLY attribute :url, Hash # READ-ONLY attribute :answers, Hash # READ-ONLY + + # v4 fields + attribute :data, String + attribute :sResponseComment, String + attribute :variable, Hash # READ-ONLY attribute :datesubmitted, DateTime - alias_attribute :submitted_at, :datesubmitted + attribute :shown, Hash # READ-ONLY + + # v5 fields + attribute :date_submitted, DateTime + attribute :date_started, DateTime + attribute :session_id, String + attribute :language, String + attribute :url_variables, Hash + attribute :survey_data, Hash + attribute :comment, Hash + attribute :subquestions, Hash + attribute :options, Hash + attribute :link_id, String + attribute :ip_address, String + attribute :referer, String + attribute :user_agent, String + attribute :response_time, Integer + attribute :data_quality, Array + attribute :longitude, String + attribute :latitude, String + attribute :country, String + attribute :city, String + attribute :region, String + attribute :postal, String + attribute :dma, Boolean @route = '/survey/:survey_id/surveyresponse' @@ -35,6 +60,10 @@ def survey @survey ||= Survey.first(id: survey_id) end + def submitted_at + datesubmitted || date_submitted + end + def parsed_answers filtered_answers = answers.select do |k, v| next false unless v.is_a?(FalseClass) || v.present? diff --git a/lib/survey_gizmo/api/survey.rb b/lib/survey_gizmo/api/survey.rb index f43a647..ea90bce 100644 --- a/lib/survey_gizmo/api/survey.rb +++ b/lib/survey_gizmo/api/survey.rb @@ -7,7 +7,6 @@ class Survey attribute :id, Integer attribute :team, Array attribute :type, String - attribute :_subtype, String attribute :status, String attribute :forward_only, Boolean attribute :title, String @@ -20,10 +19,13 @@ class Survey attribute :statistics, Array attribute :created_on, DateTime attribute :modified_on, DateTime - attribute :copy, Boolean # See comment in the #pages method for why this :pages can't be an attribute # attribute :pages, Array[Page] + # v4 fields + attribute :_subtype, String + attribute :copy, Boolean + @route = '/survey' def pages From a81c3f1b3069c094f47eb3d5261b640169cd16c2 Mon Sep 17 00:00:00 2001 From: Peter Retzlaff Date: Mon, 10 Feb 2020 21:53:02 +0100 Subject: [PATCH 02/15] Fix some API-specific fields. * teamname on AccountTeam is specific to v4. It's called team_name in v5. * answers on Response seems to be a v4-field. In v5 we get survey_data instead. --- lib/survey_gizmo/api/account_teams.rb | 3 ++- lib/survey_gizmo/api/response.rb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/survey_gizmo/api/account_teams.rb b/lib/survey_gizmo/api/account_teams.rb index 540cb7f..21c335c 100644 --- a/lib/survey_gizmo/api/account_teams.rb +++ b/lib/survey_gizmo/api/account_teams.rb @@ -6,15 +6,16 @@ class AccountTeams include SurveyGizmo::Resource attribute :id, Integer - attribute :teamname, String attribute :default_role, String attribute :status, String # v4 fields attribute :teamid, Integer + attribute :teamname, String attribute :color, Integer # v5 fields + attribute :team_name, String attribute :description, String @route = '/accountteams' diff --git a/lib/survey_gizmo/api/response.rb b/lib/survey_gizmo/api/response.rb index 7bc0843..67f44bc 100644 --- a/lib/survey_gizmo/api/response.rb +++ b/lib/survey_gizmo/api/response.rb @@ -21,9 +21,9 @@ def self.submitted_since_filter(time) attribute :is_test_data, Boolean attribute :meta, Hash # READ-ONLY attribute :url, Hash # READ-ONLY - attribute :answers, Hash # READ-ONLY # v4 fields + attribute :answers, Hash # READ-ONLY attribute :data, String attribute :sResponseComment, String attribute :variable, Hash # READ-ONLY From 8bc85105ce788df2f590a964eae7d67cad9ae572 Mon Sep 17 00:00:00 2001 From: Peter Retzlaff Date: Sat, 15 Feb 2020 18:58:19 +0100 Subject: [PATCH 03/15] Split up resource classes for v4 and v5. Separate classes into v4- and v5-submodules. Load resource files based on configuration. --- lib/survey-gizmo-ruby.rb | 1 - lib/survey_gizmo/configuration.rb | 8 ++ lib/survey_gizmo/{api => v4}/account_teams.rb | 6 +- lib/survey_gizmo/{api => v4}/answer.rb | 2 +- lib/survey_gizmo/{api => v4}/campaign.rb | 11 +-- lib/survey_gizmo/v4/contact.rb | 42 +++++++++ lib/survey_gizmo/v4/email_message.rb | 26 ++++++ lib/survey_gizmo/v4/option.rb | 15 ++++ lib/survey_gizmo/{api => v4}/page.rb | 7 +- lib/survey_gizmo/v4/question.rb | 63 +++++++++++++ lib/survey_gizmo/v4/response.rb | 63 +++++++++++++ lib/survey_gizmo/{api => v4}/survey.rb | 4 +- lib/survey_gizmo/v5/account_teams.rb | 18 ++++ lib/survey_gizmo/v5/answer.rb | 64 +++++++++++++ lib/survey_gizmo/v5/campaign.rb | 32 +++++++ lib/survey_gizmo/{api => v5}/contact.rb | 33 +------ lib/survey_gizmo/{api => v5}/email_message.rb | 9 +- lib/survey_gizmo/{api => v5}/option.rb | 2 +- lib/survey_gizmo/v5/page.rb | 37 ++++++++ lib/survey_gizmo/{api => v5}/question.rb | 10 +-- lib/survey_gizmo/{api => v5}/response.rb | 10 +-- lib/survey_gizmo/v5/survey.rb | 89 +++++++++++++++++++ 22 files changed, 470 insertions(+), 82 deletions(-) rename lib/survey_gizmo/{api => v4}/account_teams.rb (78%) rename lib/survey_gizmo/{api => v4}/answer.rb (98%) rename lib/survey_gizmo/{api => v4}/campaign.rb (76%) create mode 100644 lib/survey_gizmo/v4/contact.rb create mode 100644 lib/survey_gizmo/v4/email_message.rb create mode 100644 lib/survey_gizmo/v4/option.rb rename lib/survey_gizmo/{api => v4}/page.rb (90%) create mode 100644 lib/survey_gizmo/v4/question.rb create mode 100644 lib/survey_gizmo/v4/response.rb rename lib/survey_gizmo/{api => v4}/survey.rb (98%) create mode 100644 lib/survey_gizmo/v5/account_teams.rb create mode 100644 lib/survey_gizmo/v5/answer.rb create mode 100644 lib/survey_gizmo/v5/campaign.rb rename lib/survey_gizmo/{api => v5}/contact.rb (56%) rename lib/survey_gizmo/{api => v5}/email_message.rb (79%) rename lib/survey_gizmo/{api => v5}/option.rb (95%) create mode 100644 lib/survey_gizmo/v5/page.rb rename lib/survey_gizmo/{api => v5}/question.rb (91%) rename lib/survey_gizmo/{api => v5}/response.rb (89%) create mode 100644 lib/survey_gizmo/v5/survey.rb diff --git a/lib/survey-gizmo-ruby.rb b/lib/survey-gizmo-ruby.rb index 7bd253d..3a9a74d 100644 --- a/lib/survey-gizmo-ruby.rb +++ b/lib/survey-gizmo-ruby.rb @@ -17,4 +17,3 @@ path = File.join(File.expand_path(File.dirname(__FILE__)), 'survey_gizmo') Dir["#{path}/*.rb"].each { |f| require f } -Dir["#{path}/**/*.rb"].each { |f| require f } diff --git a/lib/survey_gizmo/configuration.rb b/lib/survey_gizmo/configuration.rb index d6f330e..8acf76a 100644 --- a/lib/survey_gizmo/configuration.rb +++ b/lib/survey_gizmo/configuration.rb @@ -32,6 +32,14 @@ def configure configuration.retriable_params = Configuration::DEFAULT_RETRIABLE_PARAMS.merge(configuration.retriable_params) @global_config = configuration + + path = File.expand_path(File.dirname(__FILE__)) + if configuration.api_version == 'v4' + Dir["#{File.join(path, 'v4')}/*.rb"].each { |f| require f } + else + Dir["#{File.join(path, 'v5')}/*.rb"].each { |f| require f } + end + configuration end def reset! diff --git a/lib/survey_gizmo/api/account_teams.rb b/lib/survey_gizmo/v4/account_teams.rb similarity index 78% rename from lib/survey_gizmo/api/account_teams.rb rename to lib/survey_gizmo/v4/account_teams.rb index 21c335c..5326d85 100644 --- a/lib/survey_gizmo/api/account_teams.rb +++ b/lib/survey_gizmo/v4/account_teams.rb @@ -1,7 +1,7 @@ # This REST endpoint is only available to accounts with admin privileges # This code is untested. -module SurveyGizmo::API +module SurveyGizmo::V4 class AccountTeams include SurveyGizmo::Resource @@ -14,10 +14,6 @@ class AccountTeams attribute :teamname, String attribute :color, Integer - # v5 fields - attribute :team_name, String - attribute :description, String - @route = '/accountteams' end end diff --git a/lib/survey_gizmo/api/answer.rb b/lib/survey_gizmo/v4/answer.rb similarity index 98% rename from lib/survey_gizmo/api/answer.rb rename to lib/survey_gizmo/v4/answer.rb index ed52e13..ad25f64 100644 --- a/lib/survey_gizmo/api/answer.rb +++ b/lib/survey_gizmo/v4/answer.rb @@ -1,4 +1,4 @@ -module SurveyGizmo::API +module SurveyGizmo::V4 class Answer include Virtus.model diff --git a/lib/survey_gizmo/api/campaign.rb b/lib/survey_gizmo/v4/campaign.rb similarity index 76% rename from lib/survey_gizmo/api/campaign.rb rename to lib/survey_gizmo/v4/campaign.rb index bfae9fd..7e287c6 100644 --- a/lib/survey_gizmo/api/campaign.rb +++ b/lib/survey_gizmo/v4/campaign.rb @@ -1,4 +1,4 @@ -module SurveyGizmo::API +module SurveyGizmo::V4 class Campaign include SurveyGizmo::Resource @@ -25,15 +25,6 @@ class Campaign attribute :surveycampaign, Integer attribute :copy, Boolean - # v5 fields - attribute :invite_id, Integer - attribute :subtype, String - attribute :link_type, String - attribute :date_created, DateTime - attribute :date_modified, DateTime - attribute :link_open_date, DateTime - attribute :link_close_date, DateTime - @route = '/survey/:survey_id/surveycampaign' def contacts(conditions = {}) diff --git a/lib/survey_gizmo/v4/contact.rb b/lib/survey_gizmo/v4/contact.rb new file mode 100644 index 0000000..d3e1162 --- /dev/null +++ b/lib/survey_gizmo/v4/contact.rb @@ -0,0 +1,42 @@ +module SurveyGizmo::V4 + class Contact + include SurveyGizmo::Resource + + attribute :id, Integer + attribute :survey_id, Integer + attribute :campaign_id, Integer + + # v4 fields + attribute :estatus, String + attribute :esubscriberstatus, String + attribute :semailaddress, String + attribute :sfirstname, String + attribute :slastname, String + attribute :sorganization, String + attribute :sdepartment, String + attribute :sbusinessphone, String + attribute :shomephone, String + attribute :sfaxphone, String + attribute :sworkphone, String + attribute :smailingaddress, String + attribute :smailingaddress2, String + attribute :smailingaddresscity, String + attribute :smailingaddressstate, String + attribute :smailingaddresscountry, String + attribute :smailingaddresspostal, String + attribute :stitle, String + attribute :surl, String + attribute :scustomfield1, String + attribute :scustomfield2, String + attribute :scustomfield3, String + attribute :scustomfield4, String + attribute :scustomfield5, String + attribute :scustomfield6, String + attribute :scustomfield7, String + attribute :scustomfield8, String + attribute :scustomfield9, String + attribute :scustomfield10, String + + @route = '/survey/:survey_id/surveycampaign/:campaign_id/contact' + end +end diff --git a/lib/survey_gizmo/v4/email_message.rb b/lib/survey_gizmo/v4/email_message.rb new file mode 100644 index 0000000..44973df --- /dev/null +++ b/lib/survey_gizmo/v4/email_message.rb @@ -0,0 +1,26 @@ +module SurveyGizmo::V4 + class EmailMessage + include SurveyGizmo::Resource + + attribute :id, Integer + attribute :survey_id, Integer + attribute :campaign_id, Integer + attribute :invite_identity, Integer + attribute :subject, String + attribute :replies, String + attribute :medium, String + attribute :status, String + attribute :from, Hash + attribute :body, Hash + attribute :send, Boolean + + # v4 fields + attribute :_type, String + attribute :_subtype, String + attribute :messagetype, String + attribute :datecreated, DateTime + attribute :datemodified, DateTime + + @route = '/survey/:survey_id/surveycampaign/:campaign_id/emailmessage' + end +end diff --git a/lib/survey_gizmo/v4/option.rb b/lib/survey_gizmo/v4/option.rb new file mode 100644 index 0000000..89aca8e --- /dev/null +++ b/lib/survey_gizmo/v4/option.rb @@ -0,0 +1,15 @@ +module SurveyGizmo::V4 + class Option + include SurveyGizmo::Resource + include SurveyGizmo::MultilingualTitle + + attribute :id, Integer + attribute :survey_id, Integer + attribute :page_id, Integer + attribute :question_id, Integer + attribute :value, String + attribute :properties, Hash + + @route = '/survey/:survey_id/surveypage/:page_id/surveyquestion/:question_id/surveyoption' + end +end diff --git a/lib/survey_gizmo/api/page.rb b/lib/survey_gizmo/v4/page.rb similarity index 90% rename from lib/survey_gizmo/api/page.rb rename to lib/survey_gizmo/v4/page.rb index da107db..b29f5b1 100644 --- a/lib/survey_gizmo/api/page.rb +++ b/lib/survey_gizmo/v4/page.rb @@ -1,6 +1,6 @@ -require 'survey_gizmo/api/question' +require 'survey_gizmo/v4/question' -module SurveyGizmo::API +module SurveyGizmo::V4 class Page include SurveyGizmo::Resource include SurveyGizmo::MultilingualTitle @@ -14,9 +14,6 @@ class Page # v4 fields attribute :after, Integer - # v5 fields - attribute :title, String - @route = '/survey/:survey_id/surveypage' def survey diff --git a/lib/survey_gizmo/v4/question.rb b/lib/survey_gizmo/v4/question.rb new file mode 100644 index 0000000..d618021 --- /dev/null +++ b/lib/survey_gizmo/v4/question.rb @@ -0,0 +1,63 @@ +require 'survey_gizmo/v4/option' + +module SurveyGizmo::V4 + class Question + include SurveyGizmo::Resource + include SurveyGizmo::MultilingualTitle + + attribute :id, Integer + attribute :type, String + attribute :description, String + attribute :shortname, String + attribute :properties, Hash + attribute :options, Array[Option] + attribute :survey_id, Integer + attribute :page_id, Integer, default: 1 + attribute :parent_question_id, Integer + + # v4 fields + attribute :after, Integer + attribute :sub_questions_skus, Array + + alias_attribute :_subtype, :type + + @route = { + get: '/survey/:survey_id/surveyquestion/:id', + create: '/survey/:survey_id/surveypage/:page_id/surveyquestion', + update: '/survey/:survey_id/surveypage/:page_id/surveyquestion/:id' + } + @route[:delete] = @route[:update] + + def survey + @survey ||= Survey.first(id: survey_id) + end + + def options + return parent_question.options.dup.each { |o| o.question_id = id } if parent_question + + @options ||= Option.all(children_params.merge(all_pages: true)).to_a + @options.each { |o| o.attributes = children_params } + end + + def parent_question + return nil unless parent_question_id + @parent_question ||= Question.first(survey_id: survey_id, id: parent_question_id) + end + + def sub_question_skus + # As of 2015-12-23, the sub_question_skus attribute can either contain an array of integers if no shortname (alias) + # was set for any question, or an array of [String, Integer] with the String corresponding to the subquestion + # shortname and the integer corresponding to the subquestion id if at least one shortname was set. + @sub_question_skus.map { |sku| sku.is_a?(Array) ? sku[1] : sku } + end + + def sub_questions + @sub_questions ||= sub_question_skus.map do |sku| + SurveyGizmo.configuration.logger.debug("Have to do individual load of sub question #{sku}...") + subquestion = Question.first(survey_id: survey_id, id: sku) + subquestion.parent_question_id = id + subquestion + end + end + end +end diff --git a/lib/survey_gizmo/v4/response.rb b/lib/survey_gizmo/v4/response.rb new file mode 100644 index 0000000..d257d33 --- /dev/null +++ b/lib/survey_gizmo/v4/response.rb @@ -0,0 +1,63 @@ +module SurveyGizmo::V4 + class Response + include SurveyGizmo::Resource + + # Filters + NO_TEST_DATA = { field: 'istestdata', operator: '<>', value: 1 } + ONLY_COMPLETED = { field: 'status', operator: '=', value: 'Complete' } + + def self.submitted_since_filter(time) + { + field: 'datesubmitted', + operator: '>=', + value: time.in_time_zone(SurveyGizmo.configuration.api_time_zone).strftime('%Y-%m-%d %H:%M:%S') + } + end + + attribute :id, Integer + attribute :survey_id, Integer + attribute :contact_id, Integer + attribute :status, String + attribute :is_test_data, Boolean + attribute :meta, Hash # READ-ONLY + attribute :url, Hash # READ-ONLY + + # v4 fields + attribute :answers, Hash # READ-ONLY + attribute :data, String + attribute :sResponseComment, String + attribute :variable, Hash # READ-ONLY + attribute :datesubmitted, DateTime + attribute :shown, Hash # READ-ONLY + + @route = '/survey/:survey_id/surveyresponse' + + def survey + @survey ||= Survey.first(id: survey_id) + end + + def submitted_at + datesubmitted || date_submitted + end + + def parsed_answers + filtered_answers = answers.select do |k, v| + next false unless v.is_a?(FalseClass) || v.present? + + # Strip out "Other" answers that don't actually have the "other" text (they come back as two responses - one + # for the "Other" option_id, and then a whole separate response for the text given as an "Other" response. + if /\[question\((?\d+)\),\s*option\((?\d+)\)\]/ =~ k + !answers.keys.any? { |key| key =~ /\[question\((#{question_id})\),\s*option\("(#{option_id})-other"\)\]/ } + elsif /\[question\((?\d+)\)\]/ =~ k + !answers.keys.any? { |key| key =~ /\[question\((#{question_id})\),\s*option\("\d+-other"\)\]/ } + else + true + end + end + + filtered_answers.map do |k, v| + Answer.new(children_params.merge(key: k, value: v, answer_text: v, submitted_at: submitted_at)) + end + end + end +end diff --git a/lib/survey_gizmo/api/survey.rb b/lib/survey_gizmo/v4/survey.rb similarity index 98% rename from lib/survey_gizmo/api/survey.rb rename to lib/survey_gizmo/v4/survey.rb index ea90bce..a0f94e1 100644 --- a/lib/survey_gizmo/api/survey.rb +++ b/lib/survey_gizmo/v4/survey.rb @@ -1,6 +1,6 @@ -require 'survey_gizmo/api/page' +require 'survey_gizmo/v4/page' -module SurveyGizmo::API +module SurveyGizmo::V4 class Survey include SurveyGizmo::Resource diff --git a/lib/survey_gizmo/v5/account_teams.rb b/lib/survey_gizmo/v5/account_teams.rb new file mode 100644 index 0000000..ce6c961 --- /dev/null +++ b/lib/survey_gizmo/v5/account_teams.rb @@ -0,0 +1,18 @@ +# This REST endpoint is only available to accounts with admin privileges +# This code is untested. + +module SurveyGizmo::V5 + class AccountTeams + include SurveyGizmo::Resource + + attribute :id, Integer + attribute :default_role, String + attribute :status, String + + # v5 fields + attribute :team_name, String + attribute :description, String + + @route = '/accountteams' + end +end diff --git a/lib/survey_gizmo/v5/answer.rb b/lib/survey_gizmo/v5/answer.rb new file mode 100644 index 0000000..8931388 --- /dev/null +++ b/lib/survey_gizmo/v5/answer.rb @@ -0,0 +1,64 @@ +module SurveyGizmo::V5 + class Answer + include Virtus.model + + attribute :key, String + attribute :value, String + attribute :survey_id, Integer + attribute :response_id, Integer + attribute :question_id, Integer + attribute :option_id, Integer + attribute :submitted_at, DateTime + attribute :answer_text, String + attribute :other_text, String + attribute :question_pipe, String + + def initialize(attrs = {}) + self.attributes = attrs + + case key + when /\[question\((\d+)\),\s*option\((\d+|"\d+-other")\)\]/ + self.question_id, self.option_id = $1, $2 + + if option_id =~ /-other/ + option_id.delete!('-other"') + self.other_text = value + elsif option_id == 0 + # Option IDs of 0 seem to happen for hidden questions, even when there is answer_text + self.option_id = nil + end + when /\[question\((\d+)\),\s*question_pipe\("?(.*)"?\)\]/ + self.question_id, self.question_pipe = $1, $2 + +# question_pipe.slice!(0) if question_pipe.starts_with?('"') + question_pipe.chop! if question_pipe.ends_with?('"') + + when /\[question\((\d+)\)\]/ + self.question_id = $1 + else + fail "Can't recognize pattern for #{attrs[:key]} => #{attrs[:value]} - you may have to parse your answers manually." + end + + self.question_id = question_id.to_i + + if option_id && !option_id.is_a?(Integer) + fail "Bad option_id #{option_id} (class: #{option_id.class}) for #{attrs}!" if option_id.to_i == 0 + self.option_id = option_id.to_i + end + end + + # Strips out the answer_text when there is a valid option_id + def to_hash + { + response_id: response_id, + question_id: question_id, + option_id: option_id, + question_pipe: question_pipe, + submitted_at: submitted_at, + survey_id: survey_id, + other_text: other_text, + answer_text: option_id || other_text ? nil : answer_text + }.reject { |k, v| v.nil? } + end + end +end diff --git a/lib/survey_gizmo/v5/campaign.rb b/lib/survey_gizmo/v5/campaign.rb new file mode 100644 index 0000000..ff83600 --- /dev/null +++ b/lib/survey_gizmo/v5/campaign.rb @@ -0,0 +1,32 @@ +module SurveyGizmo::V5 + class Campaign + include SurveyGizmo::Resource + + attribute :id, Integer + attribute :name, String + attribute :type, String + attribute :status, String + attribute :uri, String + attribute :SSL, Boolean + attribute :language, String + attribute :close_message, String + attribute :limit_responses, String + attribute :tokenvariables, Array + attribute :survey_id, Integer + + # v5 fields + attribute :invite_id, Integer + attribute :subtype, String + attribute :link_type, String + attribute :date_created, DateTime + attribute :date_modified, DateTime + attribute :link_open_date, DateTime + attribute :link_close_date, DateTime + + @route = '/survey/:survey_id/surveycampaign' + + def contacts(conditions = {}) + Contact.all(conditions.merge(children_params).merge(all_pages: !conditions[:page])) + end + end +end diff --git a/lib/survey_gizmo/api/contact.rb b/lib/survey_gizmo/v5/contact.rb similarity index 56% rename from lib/survey_gizmo/api/contact.rb rename to lib/survey_gizmo/v5/contact.rb index e547b3e..b2a8b0c 100644 --- a/lib/survey_gizmo/api/contact.rb +++ b/lib/survey_gizmo/v5/contact.rb @@ -1,4 +1,4 @@ -module SurveyGizmo::API +module SurveyGizmo::V5 class Contact include SurveyGizmo::Resource @@ -6,37 +6,6 @@ class Contact attribute :survey_id, Integer attribute :campaign_id, Integer - # v4 fields - attribute :estatus, String - attribute :esubscriberstatus, String - attribute :semailaddress, String - attribute :sfirstname, String - attribute :slastname, String - attribute :sorganization, String - attribute :sdepartment, String - attribute :sbusinessphone, String - attribute :shomephone, String - attribute :sfaxphone, String - attribute :sworkphone, String - attribute :smailingaddress, String - attribute :smailingaddress2, String - attribute :smailingaddresscity, String - attribute :smailingaddressstate, String - attribute :smailingaddresscountry, String - attribute :smailingaddresspostal, String - attribute :stitle, String - attribute :surl, String - attribute :scustomfield1, String - attribute :scustomfield2, String - attribute :scustomfield3, String - attribute :scustomfield4, String - attribute :scustomfield5, String - attribute :scustomfield6, String - attribute :scustomfield7, String - attribute :scustomfield8, String - attribute :scustomfield9, String - attribute :scustomfield10, String - # v5 fields attribute :date_last_sent, DateTime attribute :division, String diff --git a/lib/survey_gizmo/api/email_message.rb b/lib/survey_gizmo/v5/email_message.rb similarity index 79% rename from lib/survey_gizmo/api/email_message.rb rename to lib/survey_gizmo/v5/email_message.rb index 214f9cb..c645d91 100644 --- a/lib/survey_gizmo/api/email_message.rb +++ b/lib/survey_gizmo/v5/email_message.rb @@ -1,4 +1,4 @@ -module SurveyGizmo::API +module SurveyGizmo::V5 class EmailMessage include SurveyGizmo::Resource @@ -14,13 +14,6 @@ class EmailMessage attribute :body, Hash attribute :send, Boolean - # v4 fields - attribute :_type, String - attribute :_subtype, String - attribute :messagetype, String - attribute :datecreated, DateTime - attribute :datemodified, DateTime - # v5 fields attribute :type, String attribute :subtype, String diff --git a/lib/survey_gizmo/api/option.rb b/lib/survey_gizmo/v5/option.rb similarity index 95% rename from lib/survey_gizmo/api/option.rb rename to lib/survey_gizmo/v5/option.rb index e1be5c6..142445b 100644 --- a/lib/survey_gizmo/api/option.rb +++ b/lib/survey_gizmo/v5/option.rb @@ -1,4 +1,4 @@ -module SurveyGizmo::API +module SurveyGizmo::V5 class Option include SurveyGizmo::Resource include SurveyGizmo::MultilingualTitle diff --git a/lib/survey_gizmo/v5/page.rb b/lib/survey_gizmo/v5/page.rb new file mode 100644 index 0000000..751ea0a --- /dev/null +++ b/lib/survey_gizmo/v5/page.rb @@ -0,0 +1,37 @@ +require 'survey_gizmo/v5/question' + +module SurveyGizmo::V5 + class Page + include SurveyGizmo::Resource + include SurveyGizmo::MultilingualTitle + + attribute :id, Integer + attribute :description, String + attribute :properties, Hash + attribute :survey_id, Integer + attribute :questions, Array[Question] + + # v5 fields + attribute :title, String + + @route = '/survey/:survey_id/surveypage' + + def survey + @survey ||= Survey.first(id: survey_id) + end + + def questions + @questions.each { |q| q.attributes = children_params } + return @questions if @questions.all? { |q| q.sub_question_skus.all? { |sku| @questions.find { |q| q.id == sku } } } + + # See note on broken subquestions in resource.rb. + with_subquestions = @questions + @questions.each do |q| + with_subquestions.reject! { |q| q.sub_question_skus.include?(q.id) } + with_subquestions += q.sub_questions + end + + @questions = with_subquestions.each { |q| q.attributes = children_params } + end + end +end diff --git a/lib/survey_gizmo/api/question.rb b/lib/survey_gizmo/v5/question.rb similarity index 91% rename from lib/survey_gizmo/api/question.rb rename to lib/survey_gizmo/v5/question.rb index fa92fe8..1864524 100644 --- a/lib/survey_gizmo/api/question.rb +++ b/lib/survey_gizmo/v5/question.rb @@ -1,6 +1,6 @@ -require 'survey_gizmo/api/option' +require 'survey_gizmo/v5/option' -module SurveyGizmo::API +module SurveyGizmo::V5 class Question include SurveyGizmo::Resource include SurveyGizmo::MultilingualTitle @@ -15,12 +15,6 @@ class Question attribute :page_id, Integer, default: 1 attribute :parent_question_id, Integer - # v4 fields - attribute :after, Integer - attribute :sub_questions_skus, Array - - alias_attribute :_subtype, :type - # v5 fields attribute :base_type, String attribute :varname, Array diff --git a/lib/survey_gizmo/api/response.rb b/lib/survey_gizmo/v5/response.rb similarity index 89% rename from lib/survey_gizmo/api/response.rb rename to lib/survey_gizmo/v5/response.rb index 67f44bc..5fe6cc2 100644 --- a/lib/survey_gizmo/api/response.rb +++ b/lib/survey_gizmo/v5/response.rb @@ -1,4 +1,4 @@ -module SurveyGizmo::API +module SurveyGizmo::V5 class Response include SurveyGizmo::Resource @@ -22,14 +22,6 @@ def self.submitted_since_filter(time) attribute :meta, Hash # READ-ONLY attribute :url, Hash # READ-ONLY - # v4 fields - attribute :answers, Hash # READ-ONLY - attribute :data, String - attribute :sResponseComment, String - attribute :variable, Hash # READ-ONLY - attribute :datesubmitted, DateTime - attribute :shown, Hash # READ-ONLY - # v5 fields attribute :date_submitted, DateTime attribute :date_started, DateTime diff --git a/lib/survey_gizmo/v5/survey.rb b/lib/survey_gizmo/v5/survey.rb new file mode 100644 index 0000000..9a70a91 --- /dev/null +++ b/lib/survey_gizmo/v5/survey.rb @@ -0,0 +1,89 @@ +require 'survey_gizmo/v5/page' + +module SurveyGizmo::V5 + class Survey + include SurveyGizmo::Resource + + attribute :id, Integer + attribute :team, Array + attribute :type, String + attribute :status, String + attribute :forward_only, Boolean + attribute :title, String + attribute :internal_title, String + attribute :title_ml, Hash + attribute :links, Hash + attribute :theme, Integer + attribute :blockby, String + attribute :languages, Array + attribute :statistics, Array + attribute :created_on, DateTime + attribute :modified_on, DateTime + # See comment in the #pages method for why this :pages can't be an attribute + # attribute :pages, Array[Page] + + @route = '/survey' + + def pages + # SurveyGizmo sends down the page info to .first requests but NOT to .all requests, so we must load pages + # manually. We should be able to just .reload this Survey BUT we can't make :pages a Virtus attribute without + # requiring a call to this method during Survey.save + @pages ||= Page.all(children_params.merge(all_pages: true)).to_a + @pages.each { |p| p.attributes = children_params } + end + + # Sub question handling is in resource.rb and page.rb. It should probably be here instead but if it gets moved + # here and people try to request all the questions for a specific page directly from a ::API::Question request or + # from Page.questions, sub questions will not be included! So I left it there for least astonishment. + def questions + @questions ||= pages.flat_map { |p| p.questions } + end + + def actual_questions + questions.reject { |q| q.type =~ /^(instructions|urlredirect|logic|media|script|javascript)$/ } + end + + def responses(conditions = {}) + Response.all(conditions.merge(children_params).merge(all_pages: !conditions[:page])) + end + + # Statistics array of arrays looks like: + # [["Partial", 2], ["Disqualified", 28], ["Complete", 15]] + def number_of_completed_responses + if statistics && !statistics.empty? && (completed_data = statistics.find { |a| a[0] == 'Complete' }) + completed_data[1] + else + 0 + end + end + + def server_has_new_results_since?(time, filters = []) + Response.all( + children_params.merge( + page: 1, + resultsperpage: 1, + filters: filters + [Response.submitted_since_filter(time)] + ) + ).to_a.size > 0 + end + + # As of 2015-12-18, when you request data on multiple surveys from /survey, the team variable comes + # back as "0". If you request one survey at a time from /survey/{id}, it is populated correctly. + def teams + @individual_survey ||= self.reload + @individual_survey.team + end + + def team_names + teams.map { |t| t['name'] } + end + + def belongs_to?(team) + team_names.any? { |t| t == team } + end + + def campaigns + @campaigns ||= Campaign.all(children_params.merge(all_pages: true)).to_a + end + end +end From 690225c2e35babe8414492cd764f4ea4762cc0c1 Mon Sep 17 00:00:00 2001 From: Peter Retzlaff Date: Sat, 15 Feb 2020 19:06:18 +0100 Subject: [PATCH 04/15] Choose question class based on configuration. --- lib/survey_gizmo/configuration.rb | 4 ++++ lib/survey_gizmo/resource.rb | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/survey_gizmo/configuration.rb b/lib/survey_gizmo/configuration.rb index 8acf76a..f71a745 100644 --- a/lib/survey_gizmo/configuration.rb +++ b/lib/survey_gizmo/configuration.rb @@ -121,5 +121,9 @@ def region=(region) @api_url = region_infos[:url] @api_time_zone = region_infos[:locale] end + + def v5? + api_version == 'v5' + end end end diff --git a/lib/survey_gizmo/resource.rb b/lib/survey_gizmo/resource.rb index fc3f1ec..39eb563 100644 --- a/lib/survey_gizmo/resource.rb +++ b/lib/survey_gizmo/resource.rb @@ -53,7 +53,8 @@ def all(conditions = {}) # Sub questions are not pulled by default so we have to retrieve them manually. SurveyGizmo # claims they will fix this bug and eventually all questions will be returned in one request. - if self == SurveyGizmo::API::Question + question_class = SurveyGizmo.configuration.v5? ? SurveyGizmo::V5::Question : SurveyGizmo::V4::Question + if self == question_class collection += collection.flat_map { |question| question.sub_questions } end From 3a0cf710312d74134ac4743b79dc52a3050baea4 Mon Sep 17 00:00:00 2001 From: Peter Retzlaff Date: Sat, 15 Feb 2020 19:16:50 +0100 Subject: [PATCH 05/15] Restore v4 fields to original state. --- lib/survey_gizmo/v4/account_teams.rb | 6 ++---- lib/survey_gizmo/v4/campaign.rb | 12 +++++------- lib/survey_gizmo/v4/contact.rb | 2 -- lib/survey_gizmo/v4/email_message.rb | 10 +++------- lib/survey_gizmo/v4/page.rb | 4 +--- lib/survey_gizmo/v4/question.rb | 6 ++---- lib/survey_gizmo/v4/response.rb | 15 +++++---------- lib/survey_gizmo/v4/survey.rb | 6 ++---- 8 files changed, 20 insertions(+), 41 deletions(-) diff --git a/lib/survey_gizmo/v4/account_teams.rb b/lib/survey_gizmo/v4/account_teams.rb index 5326d85..7b546b5 100644 --- a/lib/survey_gizmo/v4/account_teams.rb +++ b/lib/survey_gizmo/v4/account_teams.rb @@ -6,13 +6,11 @@ class AccountTeams include SurveyGizmo::Resource attribute :id, Integer - attribute :default_role, String - attribute :status, String - - # v4 fields attribute :teamid, Integer attribute :teamname, String attribute :color, Integer + attribute :default_role, String + attribute :status, String @route = '/accountteams' end diff --git a/lib/survey_gizmo/v4/campaign.rb b/lib/survey_gizmo/v4/campaign.rb index 7e287c6..81a6d09 100644 --- a/lib/survey_gizmo/v4/campaign.rb +++ b/lib/survey_gizmo/v4/campaign.rb @@ -5,21 +5,19 @@ class Campaign attribute :id, Integer attribute :name, String attribute :type, String + attribute :_type, String + attribute :subtype, String + attribute :_subtype, String + attribute :__subtype, String attribute :status, String attribute :uri, String attribute :SSL, Boolean + attribute :slug, String attribute :language, String attribute :close_message, String attribute :limit_responses, String attribute :tokenvariables, Array attribute :survey_id, Integer - - # v4 fields - attribute :_type, String - attribute :subtype, String - attribute :_subtype, String - attribute :__subtype, String - attribute :slug, String attribute :datecreated, DateTime attribute :datemodified, DateTime attribute :surveycampaign, Integer diff --git a/lib/survey_gizmo/v4/contact.rb b/lib/survey_gizmo/v4/contact.rb index d3e1162..87d6c0a 100644 --- a/lib/survey_gizmo/v4/contact.rb +++ b/lib/survey_gizmo/v4/contact.rb @@ -5,8 +5,6 @@ class Contact attribute :id, Integer attribute :survey_id, Integer attribute :campaign_id, Integer - - # v4 fields attribute :estatus, String attribute :esubscriberstatus, String attribute :semailaddress, String diff --git a/lib/survey_gizmo/v4/email_message.rb b/lib/survey_gizmo/v4/email_message.rb index 44973df..fbc95a0 100644 --- a/lib/survey_gizmo/v4/email_message.rb +++ b/lib/survey_gizmo/v4/email_message.rb @@ -6,21 +6,17 @@ class EmailMessage attribute :survey_id, Integer attribute :campaign_id, Integer attribute :invite_identity, Integer + attribute :_type, String + attribute :_subtype, String attribute :subject, String attribute :replies, String + attribute :messagetype, String attribute :medium, String attribute :status, String attribute :from, Hash attribute :body, Hash attribute :send, Boolean - # v4 fields - attribute :_type, String - attribute :_subtype, String - attribute :messagetype, String - attribute :datecreated, DateTime - attribute :datemodified, DateTime - @route = '/survey/:survey_id/surveycampaign/:campaign_id/emailmessage' end end diff --git a/lib/survey_gizmo/v4/page.rb b/lib/survey_gizmo/v4/page.rb index b29f5b1..c64525e 100644 --- a/lib/survey_gizmo/v4/page.rb +++ b/lib/survey_gizmo/v4/page.rb @@ -8,12 +8,10 @@ class Page attribute :id, Integer attribute :description, String attribute :properties, Hash + attribute :after, Integer attribute :survey_id, Integer attribute :questions, Array[Question] - # v4 fields - attribute :after, Integer - @route = '/survey/:survey_id/surveypage' def survey diff --git a/lib/survey_gizmo/v4/question.rb b/lib/survey_gizmo/v4/question.rb index d618021..8a51b13 100644 --- a/lib/survey_gizmo/v4/question.rb +++ b/lib/survey_gizmo/v4/question.rb @@ -10,15 +10,13 @@ class Question attribute :description, String attribute :shortname, String attribute :properties, Hash + attribute :after, Integer attribute :options, Array[Option] attribute :survey_id, Integer attribute :page_id, Integer, default: 1 + attribute :sub_questions_skus, Array attribute :parent_question_id, Integer - # v4 fields - attribute :after, Integer - attribute :sub_questions_skus, Array - alias_attribute :_subtype, :type @route = { diff --git a/lib/survey_gizmo/v4/response.rb b/lib/survey_gizmo/v4/response.rb index d257d33..4fdf9e7 100644 --- a/lib/survey_gizmo/v4/response.rb +++ b/lib/survey_gizmo/v4/response.rb @@ -17,18 +17,17 @@ def self.submitted_since_filter(time) attribute :id, Integer attribute :survey_id, Integer attribute :contact_id, Integer + attribute :data, String attribute :status, String attribute :is_test_data, Boolean + attribute :sResponseComment, String + attribute :variable, Hash # READ-ONLY attribute :meta, Hash # READ-ONLY + attribute :shown, Hash # READ-ONLY attribute :url, Hash # READ-ONLY - - # v4 fields attribute :answers, Hash # READ-ONLY - attribute :data, String - attribute :sResponseComment, String - attribute :variable, Hash # READ-ONLY attribute :datesubmitted, DateTime - attribute :shown, Hash # READ-ONLY + alias_attribute :submitted_at, :datesubmitted @route = '/survey/:survey_id/surveyresponse' @@ -36,10 +35,6 @@ def survey @survey ||= Survey.first(id: survey_id) end - def submitted_at - datesubmitted || date_submitted - end - def parsed_answers filtered_answers = answers.select do |k, v| next false unless v.is_a?(FalseClass) || v.present? diff --git a/lib/survey_gizmo/v4/survey.rb b/lib/survey_gizmo/v4/survey.rb index a0f94e1..17dc4b2 100644 --- a/lib/survey_gizmo/v4/survey.rb +++ b/lib/survey_gizmo/v4/survey.rb @@ -7,6 +7,7 @@ class Survey attribute :id, Integer attribute :team, Array attribute :type, String + attribute :_subtype, String attribute :status, String attribute :forward_only, Boolean attribute :title, String @@ -19,13 +20,10 @@ class Survey attribute :statistics, Array attribute :created_on, DateTime attribute :modified_on, DateTime + attribute :copy, Boolean # See comment in the #pages method for why this :pages can't be an attribute # attribute :pages, Array[Page] - # v4 fields - attribute :_subtype, String - attribute :copy, Boolean - @route = '/survey' def pages From c0342de25db10801e8d72c3194ba4259956d21a6 Mon Sep 17 00:00:00 2001 From: Peter Retzlaff Date: Sat, 15 Feb 2020 19:19:30 +0100 Subject: [PATCH 06/15] Revert accidental changes in v4 classes. --- lib/survey_gizmo/v4/account_teams.rb | 4 ++-- lib/survey_gizmo/v4/email_message.rb | 2 ++ lib/survey_gizmo/v4/page.rb | 2 +- lib/survey_gizmo/v4/question.rb | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/survey_gizmo/v4/account_teams.rb b/lib/survey_gizmo/v4/account_teams.rb index 7b546b5..d85a483 100644 --- a/lib/survey_gizmo/v4/account_teams.rb +++ b/lib/survey_gizmo/v4/account_teams.rb @@ -6,9 +6,9 @@ class AccountTeams include SurveyGizmo::Resource attribute :id, Integer - attribute :teamid, Integer + attribute :teamid, Integer attribute :teamname, String - attribute :color, Integer + attribute :color, String attribute :default_role, String attribute :status, String diff --git a/lib/survey_gizmo/v4/email_message.rb b/lib/survey_gizmo/v4/email_message.rb index fbc95a0..424ee32 100644 --- a/lib/survey_gizmo/v4/email_message.rb +++ b/lib/survey_gizmo/v4/email_message.rb @@ -16,6 +16,8 @@ class EmailMessage attribute :from, Hash attribute :body, Hash attribute :send, Boolean + attribute :datecreated, DateTime + attribute :datemodified, DateTime @route = '/survey/:survey_id/surveycampaign/:campaign_id/emailmessage' end diff --git a/lib/survey_gizmo/v4/page.rb b/lib/survey_gizmo/v4/page.rb index c64525e..3f0cbb0 100644 --- a/lib/survey_gizmo/v4/page.rb +++ b/lib/survey_gizmo/v4/page.rb @@ -8,7 +8,7 @@ class Page attribute :id, Integer attribute :description, String attribute :properties, Hash - attribute :after, Integer + attribute :after, Integer attribute :survey_id, Integer attribute :questions, Array[Question] diff --git a/lib/survey_gizmo/v4/question.rb b/lib/survey_gizmo/v4/question.rb index 8a51b13..72a9e28 100644 --- a/lib/survey_gizmo/v4/question.rb +++ b/lib/survey_gizmo/v4/question.rb @@ -14,7 +14,7 @@ class Question attribute :options, Array[Option] attribute :survey_id, Integer attribute :page_id, Integer, default: 1 - attribute :sub_questions_skus, Array + attribute :sub_question_skus, Array attribute :parent_question_id, Integer alias_attribute :_subtype, :type From 0da1e1f0f169f8b6e0b7829eb1c5198ff1ea067b Mon Sep 17 00:00:00 2001 From: Peter Retzlaff Date: Sat, 15 Feb 2020 19:20:13 +0100 Subject: [PATCH 07/15] Add space. --- lib/survey_gizmo/v4/question.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/survey_gizmo/v4/question.rb b/lib/survey_gizmo/v4/question.rb index 72a9e28..b622187 100644 --- a/lib/survey_gizmo/v4/question.rb +++ b/lib/survey_gizmo/v4/question.rb @@ -14,7 +14,7 @@ class Question attribute :options, Array[Option] attribute :survey_id, Integer attribute :page_id, Integer, default: 1 - attribute :sub_question_skus, Array + attribute :sub_question_skus, Array attribute :parent_question_id, Integer alias_attribute :_subtype, :type From 1d493b188c732cd21d44fc4d4f7ff16953926544 Mon Sep 17 00:00:00 2001 From: Peter Retzlaff Date: Sat, 15 Feb 2020 19:53:44 +0100 Subject: [PATCH 08/15] Change accessor methods to work with the new v5 data structures. Changes are mostly copied from mkaydev's original change set. --- lib/survey_gizmo/v5/campaign.rb | 2 +- lib/survey_gizmo/v5/contact.rb | 2 +- lib/survey_gizmo/v5/page.rb | 10 ---------- lib/survey_gizmo/v5/question.rb | 16 ---------------- lib/survey_gizmo/v5/response.rb | 22 +++------------------- lib/survey_gizmo/v5/survey.rb | 4 +++- 6 files changed, 8 insertions(+), 48 deletions(-) diff --git a/lib/survey_gizmo/v5/campaign.rb b/lib/survey_gizmo/v5/campaign.rb index ff83600..8b78e27 100644 --- a/lib/survey_gizmo/v5/campaign.rb +++ b/lib/survey_gizmo/v5/campaign.rb @@ -11,10 +11,10 @@ class Campaign attribute :language, String attribute :close_message, String attribute :limit_responses, String - attribute :tokenvariables, Array attribute :survey_id, Integer # v5 fields + attribute :token_variables, Array attribute :invite_id, Integer attribute :subtype, String attribute :link_type, String diff --git a/lib/survey_gizmo/v5/contact.rb b/lib/survey_gizmo/v5/contact.rb index b2a8b0c..d36500d 100644 --- a/lib/survey_gizmo/v5/contact.rb +++ b/lib/survey_gizmo/v5/contact.rb @@ -12,7 +12,6 @@ class Contact attribute :team, String attribute :group, String attribute :role, String - attribute :status, String attribute :subscriber_status, String attribute :email_address, String @@ -41,6 +40,7 @@ class Contact attribute :customfield8, String attribute :customfield9, String attribute :customfield10, String + @route = '/survey/:survey_id/surveycampaign/:campaign_id/contact' end end diff --git a/lib/survey_gizmo/v5/page.rb b/lib/survey_gizmo/v5/page.rb index 751ea0a..3025fce 100644 --- a/lib/survey_gizmo/v5/page.rb +++ b/lib/survey_gizmo/v5/page.rb @@ -22,16 +22,6 @@ def survey def questions @questions.each { |q| q.attributes = children_params } - return @questions if @questions.all? { |q| q.sub_question_skus.all? { |sku| @questions.find { |q| q.id == sku } } } - - # See note on broken subquestions in resource.rb. - with_subquestions = @questions - @questions.each do |q| - with_subquestions.reject! { |q| q.sub_question_skus.include?(q.id) } - with_subquestions += q.sub_questions - end - - @questions = with_subquestions.each { |q| q.attributes = children_params } end end end diff --git a/lib/survey_gizmo/v5/question.rb b/lib/survey_gizmo/v5/question.rb index 1864524..52c93cb 100644 --- a/lib/survey_gizmo/v5/question.rb +++ b/lib/survey_gizmo/v5/question.rb @@ -44,21 +44,5 @@ def parent_question return nil unless parent_question_id @parent_question ||= Question.first(survey_id: survey_id, id: parent_question_id) end - - def sub_question_skus - # As of 2015-12-23, the sub_question_skus attribute can either contain an array of integers if no shortname (alias) - # was set for any question, or an array of [String, Integer] with the String corresponding to the subquestion - # shortname and the integer corresponding to the subquestion id if at least one shortname was set. - @sub_question_skus.map { |sku| sku.is_a?(Array) ? sku[1] : sku } - end - - def sub_questions - @sub_questions ||= sub_question_skus.map do |sku| - SurveyGizmo.configuration.logger.debug("Have to do individual load of sub question #{sku}...") - subquestion = Question.first(survey_id: survey_id, id: sku) - subquestion.parent_question_id = id - subquestion - end - end end end diff --git a/lib/survey_gizmo/v5/response.rb b/lib/survey_gizmo/v5/response.rb index 5fe6cc2..64e7910 100644 --- a/lib/survey_gizmo/v5/response.rb +++ b/lib/survey_gizmo/v5/response.rb @@ -45,6 +45,8 @@ def self.submitted_since_filter(time) attribute :region, String attribute :postal, String attribute :dma, Boolean + alias_attribute :submitted_at, :date_submitted + alias_attribute :answers, :survey_data @route = '/survey/:survey_id/surveyresponse' @@ -52,26 +54,8 @@ def survey @survey ||= Survey.first(id: survey_id) end - def submitted_at - datesubmitted || date_submitted - end - def parsed_answers - filtered_answers = answers.select do |k, v| - next false unless v.is_a?(FalseClass) || v.present? - - # Strip out "Other" answers that don't actually have the "other" text (they come back as two responses - one - # for the "Other" option_id, and then a whole separate response for the text given as an "Other" response. - if /\[question\((?\d+)\),\s*option\((?\d+)\)\]/ =~ k - !answers.keys.any? { |key| key =~ /\[question\((#{question_id})\),\s*option\("(#{option_id})-other"\)\]/ } - elsif /\[question\((?\d+)\)\]/ =~ k - !answers.keys.any? { |key| key =~ /\[question\((#{question_id})\),\s*option\("\d+-other"\)\]/ } - else - true - end - end - - filtered_answers.map do |k, v| + answers.map do |k, v| Answer.new(children_params.merge(key: k, value: v, answer_text: v, submitted_at: submitted_at)) end end diff --git a/lib/survey_gizmo/v5/survey.rb b/lib/survey_gizmo/v5/survey.rb index 9a70a91..0144c13 100644 --- a/lib/survey_gizmo/v5/survey.rb +++ b/lib/survey_gizmo/v5/survey.rb @@ -40,7 +40,9 @@ def questions end def actual_questions - questions.reject { |q| q.type =~ /^(instructions|urlredirect|logic|media|script|javascript)$/ } + questions.select do |q| + q.base_type == 'Question' || q.base_type == 'SurveyQuestion' + end end def responses(conditions = {}) From a6b6ff2c584082a26a1a8c234e906296803c2a16 Mon Sep 17 00:00:00 2001 From: Peter Retzlaff Date: Sun, 16 Feb 2020 15:20:32 +0100 Subject: [PATCH 09/15] Parse answers with options. Parsed answers for Radio- and Checkbox-questions expose the same interface, i.e. there's an options-field that contains all the selected options for that answer. --- lib/survey_gizmo/v5/answer.rb | 61 +++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/lib/survey_gizmo/v5/answer.rb b/lib/survey_gizmo/v5/answer.rb index 8931388..a5e4300 100644 --- a/lib/survey_gizmo/v5/answer.rb +++ b/lib/survey_gizmo/v5/answer.rb @@ -1,3 +1,5 @@ +require 'survey_gizmo/v5/option' + module SurveyGizmo::V5 class Answer include Virtus.model @@ -7,7 +9,9 @@ class Answer attribute :survey_id, Integer attribute :response_id, Integer attribute :question_id, Integer - attribute :option_id, Integer + attribute :question_text, String + attribute :question_type, String + attribute :options, Array[Option] attribute :submitted_at, DateTime attribute :answer_text, String attribute :other_text, String @@ -15,35 +19,36 @@ class Answer def initialize(attrs = {}) self.attributes = attrs + self.question_id = value['id'] + self.question_text = value['question'] + self.question_type = value['type'] - case key - when /\[question\((\d+)\),\s*option\((\d+|"\d+-other")\)\]/ - self.question_id, self.option_id = $1, $2 - - if option_id =~ /-other/ - option_id.delete!('-other"') - self.other_text = value - elsif option_id == 0 - # Option IDs of 0 seem to happen for hidden questions, even when there is answer_text - self.option_id = nil - end - when /\[question\((\d+)\),\s*question_pipe\("?(.*)"?\)\]/ - self.question_id, self.question_pipe = $1, $2 - -# question_pipe.slice!(0) if question_pipe.starts_with?('"') - question_pipe.chop! if question_pipe.ends_with?('"') - - when /\[question\((\d+)\)\]/ - self.question_id = $1 + if value['options'] + self.options = selected_options + elsif value['answer_id'] + self.options = single_option else - fail "Can't recognize pattern for #{attrs[:key]} => #{attrs[:value]} - you may have to parse your answers manually." + self.answer_text = value['answer'] end + end - self.question_id = question_id.to_i + def single_option + [ + Option.new(attributes.merge( + id: value['answer_id'], + value: value['answer'], + title: value['original_answer'] || value['answer'] + )) + ] + end - if option_id && !option_id.is_a?(Integer) - fail "Bad option_id #{option_id} (class: #{option_id.class}) for #{attrs}!" if option_id.to_i == 0 - self.option_id = option_id.to_i + def selected_options + value['options'].values.reject { |opt| opt['answer'].nil? }.map do |opt| + Option.new(attributes.merge( + id: opt['id'], + value: opt['answer'], + title: opt['option'] + )) end end @@ -52,12 +57,14 @@ def to_hash { response_id: response_id, question_id: question_id, - option_id: option_id, + question_type: question_type, + question_text: question_text, + options: options, question_pipe: question_pipe, submitted_at: submitted_at, survey_id: survey_id, other_text: other_text, - answer_text: option_id || other_text ? nil : answer_text + answer_text: options || other_text ? nil : answer_text }.reject { |k, v| v.nil? } end end From f849c4d122ec700d5c9fb28e8747f8da3de88c2e Mon Sep 17 00:00:00 2001 From: Peter Retzlaff Date: Mon, 18 Apr 2022 12:01:28 +0200 Subject: [PATCH 10/15] Set default API version to v5 and fix tests to v4. --- lib/survey_gizmo/configuration.rb | 2 +- spec/resource_spec.rb | 12 ++++++------ spec/spec_helper.rb | 4 ++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/survey_gizmo/configuration.rb b/lib/survey_gizmo/configuration.rb index f71a745..76dcac3 100644 --- a/lib/survey_gizmo/configuration.rb +++ b/lib/survey_gizmo/configuration.rb @@ -49,7 +49,7 @@ def reset! end class Configuration - DEFAULT_API_VERSION = 'v4' + DEFAULT_API_VERSION = 'v5' DEFAULT_RESULTS_PER_PAGE = 50 DEFAULT_TIMEOUT_SECONDS = 300 DEFAULT_REGION = :us diff --git a/spec/resource_spec.rb b/spec/resource_spec.rb index 5d7986f..e2174c2 100644 --- a/spec/resource_spec.rb +++ b/spec/resource_spec.rb @@ -50,7 +50,7 @@ end end - describe SurveyGizmo::API::Survey do + describe SurveyGizmo::V4::Survey do let(:create_attributes) { { title: 'Spec', type: 'survey', status: 'In Design' } } let(:get_attributes) { create_attributes.merge(first_params) } let(:update_attributes) { { title: 'Updated'} } @@ -78,7 +78,7 @@ end end - describe SurveyGizmo::API::Question do + describe SurveyGizmo::V4::Question do let(:base_params) { {survey_id: 1234, page_id: 1} } let(:create_attributes) { base_params.merge(title: 'Spec Question', type: 'radio', properties: { 'required' => true, 'option_sort' => false }) } let(:update_attributes) { base_params.merge(title: 'Updated') } @@ -190,7 +190,7 @@ end end - describe SurveyGizmo::API::Option do + describe SurveyGizmo::V4::Option do let(:survey_and_page) { {survey_id: 1234, page_id: 1} } let(:create_attributes) { survey_and_page.merge(question_id: 1, title: 'Spec Question', value: 'Spec Answer') } let(:update_attributes) { survey_and_page.merge(question_id: 1, title: 'Updated') } @@ -206,7 +206,7 @@ it_should_behave_like 'an object with errors' end - describe SurveyGizmo::API::Page do + describe SurveyGizmo::V4::Page do let(:create_attributes) { {:survey_id => 1234, :title => 'Spec Page' } } let(:get_attributes) { create_attributes.merge(:id => 1) } let(:update_attributes) { {:survey_id => 1234, :title => 'Updated'} } @@ -221,7 +221,7 @@ it_should_behave_like 'an object with errors' end - describe SurveyGizmo::API::Response do + describe SurveyGizmo::V4::Response do let(:create_attributes) { {:survey_id => 1234, :datesubmitted => "2015-04-15 05:46:30" } } let(:create_attributes_to_compare) { create_attributes.merge(:datesubmitted => Time.parse("2015-04-15 05:46:30 -0400")) } let(:get_attributes) { create_attributes.merge(:id => 1) } @@ -295,7 +295,7 @@ end end - describe SurveyGizmo::API::AccountTeams do + describe SurveyGizmo::V4::AccountTeams do pending('Need an account with admin privileges to test this') let(:create_attributes) { { teamid: 1234, teamname: 'team' } } let(:get_attributes) { create_attributes.merge(id: 1234) } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 3e64206..820146a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,6 +7,9 @@ # in ./support/ and its subdirectories. Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } +Dir["#{File.dirname(__FILE__)}/../lib/survey_gizmo/v4/*.rb"].each { |f| require f } +Dir["#{File.dirname(__FILE__)}/../lib/survey_gizmo/v5/*.rb"].each { |f| require f } + RSpec.configure do |config| config.include SurveyGizmoSpec::Methods @@ -16,6 +19,7 @@ config.api_token_secret = 'dreamword' config.retriable_params = { tries: 1, base_interval: 0 } config.logger.level = Logger::FATAL + config.api_version = 'v4' end @base = "#{SurveyGizmo.configuration.api_url}/#{SurveyGizmo.configuration.api_version}" From d443302c9ca0a038e571aa0947c006221be48302 Mon Sep 17 00:00:00 2001 From: Peter Retzlaff Date: Mon, 18 Apr 2022 12:01:40 +0200 Subject: [PATCH 11/15] Fix Response filter names for v5. --- lib/survey_gizmo/v5/response.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/survey_gizmo/v5/response.rb b/lib/survey_gizmo/v5/response.rb index 64e7910..95f7ae9 100644 --- a/lib/survey_gizmo/v5/response.rb +++ b/lib/survey_gizmo/v5/response.rb @@ -3,12 +3,12 @@ class Response include SurveyGizmo::Resource # Filters - NO_TEST_DATA = { field: 'istestdata', operator: '<>', value: 1 } + NO_TEST_DATA = { field: 'is_test_data', operator: '<>', value: 1 } ONLY_COMPLETED = { field: 'status', operator: '=', value: 'Complete' } def self.submitted_since_filter(time) { - field: 'datesubmitted', + field: 'date_submitted', operator: '>=', value: time.in_time_zone(SurveyGizmo.configuration.api_time_zone).strftime('%Y-%m-%d %H:%M:%S') } From 3da9f56a921786bb890ffc0953a58a0b132a1edb Mon Sep 17 00:00:00 2001 From: Peter Retzlaff Date: Mon, 18 Apr 2022 15:34:31 +0200 Subject: [PATCH 12/15] Preserve public class names by dynamically including the correct version files. --- lib/survey-gizmo-ruby.rb | 2 ++ lib/survey_gizmo/api/api.rb | 7 +++++++ lib/survey_gizmo/configuration.rb | 6 +----- lib/survey_gizmo/resource.rb | 2 +- lib/survey_gizmo/v5/answer.rb | 2 +- 5 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 lib/survey_gizmo/api/api.rb diff --git a/lib/survey-gizmo-ruby.rb b/lib/survey-gizmo-ruby.rb index 3a9a74d..1c8561f 100644 --- a/lib/survey-gizmo-ruby.rb +++ b/lib/survey-gizmo-ruby.rb @@ -17,3 +17,5 @@ path = File.join(File.expand_path(File.dirname(__FILE__)), 'survey_gizmo') Dir["#{path}/*.rb"].each { |f| require f } +Dir["#{path}/v4/*.rb"].each { |f| require f } +Dir["#{path}/v5/*.rb"].each { |f| require f } diff --git a/lib/survey_gizmo/api/api.rb b/lib/survey_gizmo/api/api.rb new file mode 100644 index 0000000..425ad70 --- /dev/null +++ b/lib/survey_gizmo/api/api.rb @@ -0,0 +1,7 @@ +module SurveyGizmo::API + if SurveyGizmo.configuration.v5? + include SurveyGizmo::V5 + else + include SurveyGizmo::V4 + end +end diff --git a/lib/survey_gizmo/configuration.rb b/lib/survey_gizmo/configuration.rb index 76dcac3..085cbe0 100644 --- a/lib/survey_gizmo/configuration.rb +++ b/lib/survey_gizmo/configuration.rb @@ -34,11 +34,7 @@ def configure @global_config = configuration path = File.expand_path(File.dirname(__FILE__)) - if configuration.api_version == 'v4' - Dir["#{File.join(path, 'v4')}/*.rb"].each { |f| require f } - else - Dir["#{File.join(path, 'v5')}/*.rb"].each { |f| require f } - end + require File.join(path, 'api/api') configuration end diff --git a/lib/survey_gizmo/resource.rb b/lib/survey_gizmo/resource.rb index 39eb563..47671e9 100644 --- a/lib/survey_gizmo/resource.rb +++ b/lib/survey_gizmo/resource.rb @@ -53,7 +53,7 @@ def all(conditions = {}) # Sub questions are not pulled by default so we have to retrieve them manually. SurveyGizmo # claims they will fix this bug and eventually all questions will be returned in one request. - question_class = SurveyGizmo.configuration.v5? ? SurveyGizmo::V5::Question : SurveyGizmo::V4::Question + question_class = SurveyGizmo::API::Question if self == question_class collection += collection.flat_map { |question| question.sub_questions } end diff --git a/lib/survey_gizmo/v5/answer.rb b/lib/survey_gizmo/v5/answer.rb index a5e4300..fa474b2 100644 --- a/lib/survey_gizmo/v5/answer.rb +++ b/lib/survey_gizmo/v5/answer.rb @@ -36,7 +36,7 @@ def single_option [ Option.new(attributes.merge( id: value['answer_id'], - value: value['answer'], + value: value['answer'], title: value['original_answer'] || value['answer'] )) ] From f515808c05e3f773cdb382921aac829eb018a80c Mon Sep 17 00:00:00 2001 From: Peter Retzlaff Date: Mon, 18 Apr 2022 19:30:19 +0200 Subject: [PATCH 13/15] Re-work test setup and add tests for V5 resources. --- lib/survey_gizmo/v5/answer.rb | 15 +- lib/survey_gizmo/v5/question.rb | 2 + spec/configuration_spec.rb | 1 + spec/logger_spec.rb | 1 + spec/resource_spec.rb | 1 + spec/resource_v5_spec.rb | 301 ++++++++++++++++++++++++++++++++ spec/spec_helper.rb | 5 +- 7 files changed, 315 insertions(+), 11 deletions(-) create mode 100644 spec/resource_v5_spec.rb diff --git a/lib/survey_gizmo/v5/answer.rb b/lib/survey_gizmo/v5/answer.rb index fa474b2..d7b0fb6 100644 --- a/lib/survey_gizmo/v5/answer.rb +++ b/lib/survey_gizmo/v5/answer.rb @@ -24,9 +24,7 @@ def initialize(attrs = {}) self.question_type = value['type'] if value['options'] - self.options = selected_options - elsif value['answer_id'] - self.options = single_option + self.answer_text = selected_options_texts.join(', ') else self.answer_text = value['answer'] end @@ -42,6 +40,12 @@ def single_option ] end + def selected_options_texts + selected_options.map do |opt| + opt['answer'] + end + end + def selected_options value['options'].values.reject { |opt| opt['answer'].nil? }.map do |opt| Option.new(attributes.merge( @@ -57,14 +61,11 @@ def to_hash { response_id: response_id, question_id: question_id, - question_type: question_type, - question_text: question_text, - options: options, question_pipe: question_pipe, submitted_at: submitted_at, survey_id: survey_id, other_text: other_text, - answer_text: options || other_text ? nil : answer_text + answer_text: other_text ? nil : answer_text }.reject { |k, v| v.nil? } end end diff --git a/lib/survey_gizmo/v5/question.rb b/lib/survey_gizmo/v5/question.rb index 52c93cb..fabf206 100644 --- a/lib/survey_gizmo/v5/question.rb +++ b/lib/survey_gizmo/v5/question.rb @@ -17,6 +17,7 @@ class Question # v5 fields attribute :base_type, String + attribute :subtype, String attribute :varname, Array attribute :has_showhide_deps, Boolean attribute :comment, Boolean @@ -42,6 +43,7 @@ def options def parent_question return nil unless parent_question_id + @parent_question ||= Question.first(survey_id: survey_id, id: parent_question_id) end end diff --git a/spec/configuration_spec.rb b/spec/configuration_spec.rb index 65efd60..9652813 100644 --- a/spec/configuration_spec.rb +++ b/spec/configuration_spec.rb @@ -5,6 +5,7 @@ let(:api_token) { "token" } let(:api_token_secret) { "doken" } + let(:test_api_version) { 'v4' } before(:each) do SurveyGizmo.configure do |config| diff --git a/spec/logger_spec.rb b/spec/logger_spec.rb index 0c00333..76194c3 100644 --- a/spec/logger_spec.rb +++ b/spec/logger_spec.rb @@ -4,6 +4,7 @@ let(:progname) { 'TEST' } let(:severity) { 'INFO' } let(:time_string) { '2015-04-15 05:46:30' } + let(:test_api_version) { 'v4' } before(:each) do SurveyGizmo.configure do |config| diff --git a/spec/resource_spec.rb b/spec/resource_spec.rb index e2174c2..6ca28de 100644 --- a/spec/resource_spec.rb +++ b/spec/resource_spec.rb @@ -3,6 +3,7 @@ describe 'Survey Gizmo Resource' do let(:create_attributes_to_compare) { } let(:get_attributes_to_compare) { } + let(:test_api_version) { 'v4' } describe SurveyGizmo::Resource do let(:described_class) { SurveyGizmoSpec::ResourceTest } diff --git a/spec/resource_v5_spec.rb b/spec/resource_v5_spec.rb new file mode 100644 index 0000000..8cd0812 --- /dev/null +++ b/spec/resource_v5_spec.rb @@ -0,0 +1,301 @@ +require 'spec_helper' + +describe 'Survey Gizmo Resource V5' do + let(:create_attributes_to_compare) { } + let(:get_attributes_to_compare) { } + let(:test_api_version) { 'v5' } + + describe SurveyGizmo::Resource do + let(:described_class) { SurveyGizmoSpec::ResourceTest } + let(:create_attributes) { { title: 'Spec', test_id: 5 } } + let(:update_attributes) { { title: 'Updated' } } + let(:first_params) { { id: 1, test_id: 5 } } + let(:get_attributes) { create_attributes.merge(id: 1) } + let(:uri_paths){ + { + get: '/test/1', + create: '/test/5/resource', + update: '/test/5/resource/1', + delete: '/test/5/resource/1' + } + } + + it '#reload' do + stub_request(:get, /#{@base}/).to_return(json_response(true, get_attributes)) + obj = described_class.new(get_attributes.merge(update_attributes)) + expect(obj.attributes.reject { |k, v| v.blank? }).to eq(get_attributes.merge(update_attributes)) + obj.reload + expect(obj.attributes.reject { |k, v| v.blank? }).to eq(get_attributes) + end + + it 'should raise an error if params are missing' do + expect(lambda { + SurveyGizmoSpec::ResourceTest.destroy(test_id: 5) + }).to raise_error(SurveyGizmo::URLError, 'Missing RESTful parameters in request: `:id`') + end + + it_should_behave_like 'an API object' + it_should_behave_like 'an object with errors' + + context '#filters_to_query_string' do + let(:page) { 2 } + let(:filters) { { page: page, filters: [{ field: 'istestdata', operator: '<>', value: 1 }] } } + + it 'should generate the correct page request' do + expect(SurveyGizmoSpec::ResourceTest.send(:filters_to_query_string, { page: page })).to eq("?page=#{page}") + end + + it 'should generate the correct filter fragment' do + expect(SurveyGizmoSpec::ResourceTest.send(:filters_to_query_string, filters)).to eq("?filter%5Bfield%5D%5B0%5D=istestdata&filter%5Boperator%5D%5B0%5D=%3C%3E&filter%5Bvalue%5D%5B0%5D=1&page=#{page}") + end + end + end + + describe SurveyGizmo::V5::Survey do + let(:create_attributes) { { title: 'Spec', type: 'survey', status: 'In Design' } } + let(:get_attributes) { create_attributes.merge(first_params) } + let(:update_attributes) { { title: 'Updated'} } + let(:first_params) { { id: 1234} } + let(:uri_paths){ + h = { :create => '/survey' } + h.default = '/survey/1234' + h + } + + it_should_behave_like 'an API object' + it_should_behave_like 'an object with errors' + + it 'should parse the number of completed records correctly' do + survey = described_class.new('statistics' => [['Partial', 2], ['Disqualified', 28], ['Complete', 15]]) + expect(survey.number_of_completed_responses).to eq(15) + end + + it 'should determine if there are new results' do + stub_request(:get, /#{@base}\/survey\/1\/surveyresponse/).to_return(json_response(true, [])) + + survey = described_class.new(id: 1) + expect(survey.server_has_new_results_since?(Time.now)).to be_falsey + expect(a_request(:get, /#{@base}\/survey\/1\/surveyresponse/)).to have_been_made + end + end + + describe SurveyGizmo::V5::Question do + let(:base_params) { {survey_id: 1234, page_id: 1} } + let(:create_attributes) { base_params.merge(title: 'Spec Question', type: 'radio', properties: { 'required' => true, 'option_sort' => false }) } + let(:update_attributes) { base_params.merge(title: 'Updated') } + let(:first_params) { base_params.merge(id: 1) } + let(:get_attributes) { create_attributes.merge(id: 1).reject { |k, v| k == :properties } } + let(:uri_paths) { + { :get => '/survey/1234/surveyquestion/1', + :create => '/survey/1234/surveypage/1/surveyquestion', + :update => '/survey/1234/surveypage/1/surveyquestion/1', + :delete => '/survey/1234/surveypage/1/surveyquestion/1' + } + } + + it_should_behave_like 'an API object' + it_should_behave_like 'an object with errors' + + it 'should handle the title hash returned from the API' do + expect(described_class.new('title' => {'English' => 'Some title'}).title).to eq('Some title') + end + + it 'should find the survey' do + stub_request(:get, /#{@base}\/survey\/1234/).to_return(json_response(true, get_attributes)) + described_class.new(base_params).survey + expect(a_request(:get, /#{@base}\/survey\/1234/)).to have_been_made + end + + context 'options' do + let(:survey_id) { 15 } + let(:question_id) { 23 } + let(:body_data) do + { + "id" => question_id, + "title" => {"English"=>"How likely are you to bang your head to Bohemian Rhapsody?"}, + "options"=> + [ + { + "id" => 10014, + "title" => {"English"=>"0 = Not at all likely"}, + "value" => "0 = Not at all likely" + }, + { + "id" => 10015, + "title" => {"English"=>"1"}, + "value" => "1" + } + ] + } + end + + context 'option parsing' do + before do + stub_request(:get, /#{@base}\/survey\/#{survey_id}\/surveyquestion\/#{question_id}/).to_return(json_response(true, body_data)) + end + + it 'correctly parses options out of question data' do + question = described_class.first(survey_id: survey_id, id: question_id) + expect(question.options.all? { |o| o.question_id == question_id && o.survey_id == survey_id }).to be_truthy + expect(question.options.map { |o| o.id }).to eq([10014, 10015]) + expect(a_request(:get, /#{@base}\/.*surveyoption/)).to_not have_been_made + end + + it 'correctly parses sub question options' do + question = described_class.new(survey_id: survey_id, id: question_id + 1, parent_question_id: question_id) + expect(question.parent_question.id).to eq(described_class.new(body_data).id) + expect(question.options.all? { |o| o.question_id == question.id && o.survey_id == survey_id }).to be_truthy + expect(question.options.map { |o| o.id }).to eq([10014, 10015]) + expect(a_request(:get, /#{@base}\/survey\/#{survey_id}\/surveyquestion\/#{question_id}/)).to have_been_made + end + end + end + + context 'subquestions' do + let(:parent_id) { 33 } + let(:subquestions) { + [ + described_class.new(id: 544, survey_id: 1234, parent_question_id: parent_id), + described_class.new(id: 322, survey_id: 1234, parent_question_id: parent_id) + ] + } + let(:question_with_subquestions) { described_class.new(id: parent_id, survey_id: 1234, sub_questions: subquestions) } + + it 'should have no subquestions' do + expect(described_class.new.sub_questions).to eq([]) + end + + it 'should have 2 subquestions and they should have the right parent question' do + stub_request(:get, /#{@base}/).to_return(json_response(true, get_attributes)) + expect(question_with_subquestions.sub_questions.size).to eq(2) + + question_with_subquestions.sub_questions.first.parent_question + question_with_subquestions.sub_questions.last.parent_question + expect(a_request(:get, /#{@base}\/survey\/1234\/surveyquestion\/#{parent_id}/)).to have_been_made.twice + end + + context 'and shortname' do + let(:sku) { 6 } + let(:subquestions) { + [ + described_class.new(id: 6, shortname: '0', survey_id: 1234, parent_question_id: parent_id), + described_class.new(id: 8, shortname: 'foo', survey_id: 1234, parent_question_id: parent_id) + ] + } + let(:question_with_subquestions) { described_class.new(id: parent_id, survey_id: 1234, sub_questions: subquestions) } + + it 'should have 2 subquestions and they should have the right parent question' do + stub_request(:get, /#{@base}/).to_return(json_response(true, get_attributes)) + expect(question_with_subquestions.sub_questions.size).to eq(2) + + question_with_subquestions.sub_questions.first.parent_question + expect(a_request(:get, /#{@base}\/survey\/1234\/surveyquestion\/#{parent_id}/)).to have_been_made + end + end + end + end + + describe SurveyGizmo::V5::Option do + let(:survey_and_page) { {survey_id: 1234, page_id: 1} } + let(:create_attributes) { survey_and_page.merge(question_id: 1, title: 'Spec Question', value: 'Spec Answer') } + let(:update_attributes) { survey_and_page.merge(question_id: 1, title: 'Updated') } + let(:first_params) { survey_and_page.merge(id: 1, question_id: 1) } + let(:get_attributes) { create_attributes.merge(id: 1) } + let(:uri_paths) { + h = { :create => '/survey/1234/surveypage/1/surveyquestion/1/surveyoption' } + h.default = '/survey/1234/surveypage/1/surveyquestion/1/surveyoption/1' + h + } + + it_should_behave_like 'an API object' + it_should_behave_like 'an object with errors' + end + + describe SurveyGizmo::V5::Page do + let(:create_attributes) { {:survey_id => 1234, :title => 'Spec Page' } } + let(:get_attributes) { create_attributes.merge(:id => 1) } + let(:update_attributes) { {:survey_id => 1234, :title => 'Updated'} } + let(:first_params) { {:id => 1, :survey_id => 1234 } } + let(:uri_paths){ + h = { :create => '/survey/1234/surveypage' } + h.default = '/survey/1234/surveypage/1' + h + } + + it_should_behave_like 'an API object' + it_should_behave_like 'an object with errors' + end + + describe SurveyGizmo::V5::Response do + # date_submitted is specified as DateTime, not Time + let(:create_attributes) { {:survey_id => 1234, :date_submitted => "2015-04-15 05:46:30 -0400" } } + let(:create_attributes_to_compare) { create_attributes.merge(:date_submitted => DateTime.parse("2015-04-15 05:46:30 -0400")) } + let(:get_attributes) { create_attributes.merge(:id => 1) } + let(:get_attributes_to_compare) { create_attributes_to_compare.merge(:id => 1) } + let(:update_attributes) { {:survey_id => 1234, :title => 'Updated'} } + let(:first_params) { {:id => 1, :survey_id => 1234 } } + let(:uri_paths){ + h = { :create => '/survey/1234/surveyresponse' } + h.default = '/survey/1234/surveyresponse/1' + h + } + + it_should_behave_like 'an API object' + it_should_behave_like 'an object with errors' + + context 'during EST' do + let(:create_attributes) { {:survey_id => 1234, :date_submitted => "2015-01-15 05:46:30 -0500" } } + let(:create_attributes_to_compare) { create_attributes.merge(:date_submitted => DateTime.parse("2015-01-15 05:46:30 -0500")) } + + it_should_behave_like 'an API object' + it_should_behave_like 'an object with errors' + end + + context 'answers' do + let(:survey_id) { 6 } + let(:response_id) { 7 } + let(:timestamp) { '2015-01-02'.to_time(:utc) } + let(:answers) do + { + 5 => { + 'id' => 5, + 'type' => "TEXTBOX", + 'shown' => true, + 'answer' => 'VERY important' + }, + 6 => { + 'id' => 6, + 'type' => "TEXTBOX", + 'shown' => false + } + } + end + + it 'should propagate time, survey_id, and response_id' do + response = described_class.new( + answers: answers.select { |k, v| k == 5}, + survey_id: survey_id, + id: response_id, + submitted_at: timestamp + ) + expect(response.parsed_answers.map { |a| a.to_hash }).to eq([ { survey_id: survey_id, response_id: response_id, question_id: 5, answer_text: "VERY important", submitted_at: timestamp }]) + end + end + end + + describe SurveyGizmo::V5::AccountTeams do + pending('Need an account with admin privileges to test this') + let(:create_attributes) { { team_name: 'team' } } + let(:get_attributes) { create_attributes.merge(id: 1234) } + let(:update_attributes) { get_attributes } + let(:first_params) { get_attributes } + let(:uri_paths) do + h = { :create => '/accountteams' } + h.default = '/accountteams/1234' + h + end + + it_should_behave_like 'an API object' + it_should_behave_like 'an object with errors' + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 820146a..f60b11b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,9 +7,6 @@ # in ./support/ and its subdirectories. Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } -Dir["#{File.dirname(__FILE__)}/../lib/survey_gizmo/v4/*.rb"].each { |f| require f } -Dir["#{File.dirname(__FILE__)}/../lib/survey_gizmo/v5/*.rb"].each { |f| require f } - RSpec.configure do |config| config.include SurveyGizmoSpec::Methods @@ -19,7 +16,7 @@ config.api_token_secret = 'dreamword' config.retriable_params = { tries: 1, base_interval: 0 } config.logger.level = Logger::FATAL - config.api_version = 'v4' + config.api_version = test_api_version end @base = "#{SurveyGizmo.configuration.api_url}/#{SurveyGizmo.configuration.api_version}" From 26fd4030a7a160ecabb5ceceb8d6c6dc2e4ea75a Mon Sep 17 00:00:00 2001 From: Peter Retzlaff Date: Sun, 24 Apr 2022 11:58:49 +0200 Subject: [PATCH 14/15] Add v5 time fields to the faraday middleware. --- lib/survey_gizmo/faraday_middleware/parse_survey_gizmo.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/survey_gizmo/faraday_middleware/parse_survey_gizmo.rb b/lib/survey_gizmo/faraday_middleware/parse_survey_gizmo.rb index ee65c7b..69866e3 100644 --- a/lib/survey_gizmo/faraday_middleware/parse_survey_gizmo.rb +++ b/lib/survey_gizmo/faraday_middleware/parse_survey_gizmo.rb @@ -19,6 +19,9 @@ class ParseSurveyGizmo < FaradayMiddleware::ResponseMiddleware 'datecreated', 'datemodified', 'datesubmitted', + 'date_created', + 'date_modified', + 'date_submitted', 'modified_on' ] From 8313bd1843ac1b0d0ccc134ac35ee858fb79b532 Mon Sep 17 00:00:00 2001 From: Peter Retzlaff Date: Sun, 24 Apr 2022 11:59:28 +0200 Subject: [PATCH 15/15] Revert unnecessary change in Resource class. --- lib/survey_gizmo/resource.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/survey_gizmo/resource.rb b/lib/survey_gizmo/resource.rb index 47671e9..fc3f1ec 100644 --- a/lib/survey_gizmo/resource.rb +++ b/lib/survey_gizmo/resource.rb @@ -53,8 +53,7 @@ def all(conditions = {}) # Sub questions are not pulled by default so we have to retrieve them manually. SurveyGizmo # claims they will fix this bug and eventually all questions will be returned in one request. - question_class = SurveyGizmo::API::Question - if self == question_class + if self == SurveyGizmo::API::Question collection += collection.flat_map { |question| question.sub_questions } end