qualtrics 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/.env.example +3 -0
  3. data/.gitignore +23 -0
  4. data/.rspec +1 -0
  5. data/Gemfile +7 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +29 -0
  8. data/Rakefile +7 -0
  9. data/lib/qualtrics.rb +52 -0
  10. data/lib/qualtrics/configuration.rb +17 -0
  11. data/lib/qualtrics/distribution.rb +90 -0
  12. data/lib/qualtrics/entity.rb +55 -0
  13. data/lib/qualtrics/mailer.rb +111 -0
  14. data/lib/qualtrics/message.rb +75 -0
  15. data/lib/qualtrics/operation.rb +77 -0
  16. data/lib/qualtrics/panel.rb +69 -0
  17. data/lib/qualtrics/panel_import.rb +41 -0
  18. data/lib/qualtrics/panel_import_file.rb +28 -0
  19. data/lib/qualtrics/recipient.rb +109 -0
  20. data/lib/qualtrics/recipient_import_row.rb +40 -0
  21. data/lib/qualtrics/response.rb +35 -0
  22. data/lib/qualtrics/survey.rb +80 -0
  23. data/lib/qualtrics/survey_import.rb +26 -0
  24. data/lib/qualtrics/transaction.rb +70 -0
  25. data/lib/qualtrics/version.rb +3 -0
  26. data/qualtrics.gemspec +34 -0
  27. data/spec/fixtures/sample_survey.xml +2 -0
  28. data/spec/fixtures/vcr_cassettes/Qualtrics_Distribution/creating_to_qualtrics/can_retrieve_a_panel_of_distributions_in_qualtrics.yml +655 -0
  29. data/spec/fixtures/vcr_cassettes/Qualtrics_Distribution/creating_to_qualtrics/can_update_itself.yml +599 -0
  30. data/spec/fixtures/vcr_cassettes/Qualtrics_Mailer/creating_to_qualtrics/sends_a_reminder_to_a_distribution.yml +493 -0
  31. data/spec/fixtures/vcr_cassettes/Qualtrics_Mailer/creating_to_qualtrics/sends_a_survey_to_a_panel_and_creates_a_distribution.yml +441 -0
  32. data/spec/fixtures/vcr_cassettes/Qualtrics_Mailer/creating_to_qualtrics/sends_a_survey_to_an_individual_and_creates_a_distribution.yml +441 -0
  33. data/spec/fixtures/vcr_cassettes/Qualtrics_Message/creating_to_qualtrics/persists_to_qualtrics.yml +56 -0
  34. data/spec/fixtures/vcr_cassettes/Qualtrics_Message/creating_to_qualtrics/populates_the_message_id_when_successful.yml +56 -0
  35. data/spec/fixtures/vcr_cassettes/Qualtrics_Message/creating_to_qualtrics/populates_the_success_attribute.yml +56 -0
  36. data/spec/fixtures/vcr_cassettes/Qualtrics_Message/retrieves_an_array_of_all_panels_in_a_library.yml +115 -0
  37. data/spec/fixtures/vcr_cassettes/Qualtrics_Panel/creating_to_qualtrics/persists_to_qualtrics.yml +107 -0
  38. data/spec/fixtures/vcr_cassettes/Qualtrics_Panel/creating_to_qualtrics/populates_the_panel_id_when_successful.yml +107 -0
  39. data/spec/fixtures/vcr_cassettes/Qualtrics_Panel/creating_to_qualtrics/populates_the_success_attribute.yml +107 -0
  40. data/spec/fixtures/vcr_cassettes/Qualtrics_Panel/destroys_a_panel_that_returns_true_when_successful.yml +107 -0
  41. data/spec/fixtures/vcr_cassettes/Qualtrics_Panel/raises_an_error_when_you_attempt_to_save_an_already_presisted_panel.yml +55 -0
  42. data/spec/fixtures/vcr_cassettes/Qualtrics_Panel/retrieves_an_array_of_all_panels_in_a_library.yml +704 -0
  43. data/spec/fixtures/vcr_cassettes/Qualtrics_PanelImport/transmits_to_qualtrics.yml +72 -0
  44. data/spec/fixtures/vcr_cassettes/Qualtrics_Recipient/creating_to_qualtrics/persists_to_qualtrics.yml +159 -0
  45. data/spec/fixtures/vcr_cassettes/Qualtrics_Recipient/creating_to_qualtrics/populates_the_recipient_id_when_successful.yml +159 -0
  46. data/spec/fixtures/vcr_cassettes/Qualtrics_Recipient/creating_to_qualtrics/populates_the_success_attribute.yml +159 -0
  47. data/spec/fixtures/vcr_cassettes/Qualtrics_Recipient/creating_to_qualtrics/raises_an_error_when_a_recipient_is_created_without_specifying_a_panel_id.yml +107 -0
  48. data/spec/fixtures/vcr_cassettes/Qualtrics_Recipient/recipient_made_in_qualtrics/can_delete_itself_in_qualtrics.yml +311 -0
  49. data/spec/fixtures/vcr_cassettes/Qualtrics_Recipient/recipient_made_in_qualtrics/can_update_itself_in_qualtrics.yml +313 -0
  50. data/spec/fixtures/vcr_cassettes/Qualtrics_Recipient/recipient_made_in_qualtrics/gets_its_information_in_qualtrics.yml +209 -0
  51. data/spec/fixtures/vcr_cassettes/Qualtrics_Survey/creating_to_qualtrics/can_be_activated_or_deactivated.yml +232 -0
  52. data/spec/fixtures/vcr_cassettes/Qualtrics_Survey/creating_to_qualtrics/destroys_a_survey_that_returns_true_when_successful.yml +128 -0
  53. data/spec/fixtures/vcr_cassettes/Qualtrics_Survey/creating_to_qualtrics/populates_the_survey_id_when_successful.yml +128 -0
  54. data/spec/fixtures/vcr_cassettes/Qualtrics_Survey/creating_to_qualtrics/retrieves_an_array_of_all_surveys.yml +203 -0
  55. data/spec/fixtures/vcr_cassettes/Qualtrics_SurveyImport/transmits_to_qualtrics.yml +128 -0
  56. data/spec/qualtrics/configuration_spec.rb +53 -0
  57. data/spec/qualtrics/distribution_spec.rb +144 -0
  58. data/spec/qualtrics/mailer_spec.rb +127 -0
  59. data/spec/qualtrics/message_spec.rb +105 -0
  60. data/spec/qualtrics/panel_import_file_spec.rb +26 -0
  61. data/spec/qualtrics/panel_import_spec.rb +43 -0
  62. data/spec/qualtrics/panel_spec.rb +80 -0
  63. data/spec/qualtrics/recipient_import_row_spec.rb +62 -0
  64. data/spec/qualtrics/recipient_spec.rb +185 -0
  65. data/spec/qualtrics/response_spec.rb +41 -0
  66. data/spec/qualtrics/survey_import_spec.rb +44 -0
  67. data/spec/qualtrics/survey_spec.rb +125 -0
  68. data/spec/spec_helper.rb +11 -0
  69. data/spec/support/_dotenv.rb +2 -0
  70. data/spec/support/qualtrics.rb +5 -0
  71. data/spec/support/vcr.rb +11 -0
  72. metadata +330 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 38dac26d3a42c7605dbcd2719a27c619dcc50d7c
4
+ data.tar.gz: dbdf572cb5c95ec562aa25175ea5e96645ddccdd
5
+ SHA512:
6
+ metadata.gz: da1cae4b7d293c3166293df258060c70554ce125118b98c996526105f9ee81f311dc6648173ba057ccd2cf697956087dd5ae6043ca11762bc6cbbd60ece82cd3
7
+ data.tar.gz: 2c311bd28014ed213781f64b3629942cc1d6a8af72e1e3cf6bcace3df7d0cb2d2a766ea75f7d24ecccbaa9d64e519c3555da0cd8fe08ccd12708b94917f21bee
data/.env.example ADDED
@@ -0,0 +1,3 @@
1
+ QUALTRICS_USER=''
2
+ QUALTRICS_TOKEN=''
3
+ QUALTRICS_LIBRARY_ID=''
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ .env
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in qualtrics.gemspec
4
+ gemspec
5
+ group :development do
6
+ gem 'pry'
7
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Kevin Sun
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Qualtrics
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'qualtrics'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install qualtrics
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( https://github.com/[my-github-username]/qualtrics/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
data/lib/qualtrics.rb ADDED
@@ -0,0 +1,52 @@
1
+ require 'configatron'
2
+
3
+ require "qualtrics/configuration"
4
+ require "qualtrics/version"
5
+ require "qualtrics/operation"
6
+ require "qualtrics/response"
7
+ require "qualtrics/entity"
8
+ require "qualtrics/recipient"
9
+ require "qualtrics/panel"
10
+ require "qualtrics/panel_import"
11
+ require "qualtrics/survey"
12
+ require "qualtrics/survey_import"
13
+
14
+ require "qualtrics/message"
15
+ require "qualtrics/distribution"
16
+ require "qualtrics/mailer"
17
+
18
+ # not always necessary for runtime
19
+ # consider adding only when necessary
20
+ require "qualtrics/transaction"
21
+
22
+ module Qualtrics
23
+ def self.configure(&block)
24
+ configuration.update(&block)
25
+ end
26
+
27
+ def self.configuration
28
+ if !configatron.has_key?(:qualtrics)
29
+ configatron.qualtrics = Configuration.new
30
+ end
31
+ configatron.qualtrics
32
+ end
33
+
34
+ class << self
35
+ def begin_transaction!
36
+ configatron.qualtrics_transaction = Qualtrics::Transaction.new
37
+ Qualtrics::Operation.add_listener(configatron.qualtrics_transaction)
38
+ end
39
+
40
+ def rollback_transaction!
41
+ if configatron.has_key?(:qualtrics_transaction)
42
+ configatron.qualtrics_transaction.rollback!
43
+ Qualtrics::Operation.delete_listener(configatron.qualtrics_transaction)
44
+ end
45
+ end
46
+ end
47
+
48
+ class Error < StandardError; end
49
+ class ServerErrorEncountered < Error; end
50
+ class UpdateNotAllowed < Error; end
51
+ class UnexpectedRequestMethod < Error; end
52
+ end
@@ -0,0 +1,17 @@
1
+ module Qualtrics
2
+ class Configuration
3
+ attr_accessor :version, :user, :token, :library_id, :endpoint, :default_library_id
4
+ DEFAULT_VERSION = '2.3'
5
+ DEFAULT_ENDPOINT = 'https://co1.qualtrics.com/WRAPI/ControlPanel/api.php'
6
+
7
+ def initialize(&block)
8
+ block.call(self) if block_given?
9
+ self.version ||= DEFAULT_VERSION
10
+ self.endpoint ||= DEFAULT_ENDPOINT
11
+ end
12
+
13
+ def update(&block)
14
+ block.call(self) if block_given?
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,90 @@
1
+ module Qualtrics
2
+ class Distribution < Entity
3
+
4
+ include ActiveModel::Validations
5
+
6
+ validates :id, presence: true
7
+ validates :message_id, presence: true
8
+ validates :survey_id, presence: true
9
+
10
+ attr_accessor :id, :survey_id, :message_id,
11
+ :emails_sent, :emails_failed, :emails_responded,
12
+ :emails_bounced, :emails_opened, :emails_skipped
13
+
14
+ def initialize(options={})
15
+ @id = options[:id]
16
+ @message_id = options[:message_id]
17
+ @survey_id = options[:survey_id]
18
+ set_email_response_data(options)
19
+ end
20
+
21
+ def set_email_response_data(options={})
22
+ @emails_sent = options[:emails_sent]
23
+ @emails_failed = options[:emails_failed]
24
+ @emails_responded = options[:emails_responded]
25
+ @emails_bounced = options[:emails_bounced]
26
+ @emails_opened = options[:emails_opened]
27
+ @emails_skipped = options[:emails_skipped]
28
+ end
29
+
30
+ def self.attributes
31
+ {
32
+ 'EmailDistributionID' => :id,
33
+ 'MessageID' => :message_id,
34
+ 'SurveyID' => :survey_id,
35
+ 'EmailsSent' => :emails_sent,
36
+ 'EmailsFailed' => :emails_failed,
37
+ 'EmailsResponded' => :emails_responded,
38
+ 'EmailsBounced' => :emails_bounced,
39
+ 'EmailsOpened' => :emails_opened,
40
+ 'EmailsSkipped' => :emails_skipped
41
+ }
42
+ end
43
+
44
+ def refresh
45
+ response = get('getDistributions',
46
+ {
47
+ 'SurveyID' => survey_id,
48
+ 'DistributionID' => id,
49
+ 'LibraryID' => library_id
50
+ }
51
+ )
52
+
53
+ if response.success?
54
+ distribution_hash = response.result['Distributions']
55
+ set_email_response_data(self.class.response_hash(distribution_hash ))
56
+ true
57
+ else
58
+ false
59
+ end
60
+ end
61
+
62
+ def self.get_distribution_with_panel(panel, survey, library_id = configuration.default_library_id)
63
+ response = get('getDistributions',
64
+ {
65
+ 'SurveyID' => survey.id,
66
+ 'PanelID' => panel.id,
67
+ 'LibraryID' => library_id
68
+ }
69
+ )
70
+
71
+ if response.success?
72
+ response.result['Distributions'].map do |distribution|
73
+ Qualtrics::Distribution.new(response_hash(distribution))
74
+ end
75
+ else
76
+ false
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ def self.response_hash(distribution_response)
83
+ {}.tap do |result|
84
+ attributes.each do |k,v|
85
+ result[v] = distribution_response[k]
86
+ end
87
+ end.delete_if {|key, value| value.nil? }
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,55 @@
1
+ require 'active_model'
2
+ module Qualtrics
3
+ class Entity
4
+ include ActiveModel::Model
5
+ include ActiveModel::Validations
6
+
7
+ def library_id=(lib_id)
8
+ @library_id = lib_id
9
+ end
10
+
11
+ def library_id
12
+ @library_id || configuration.default_library_id
13
+ end
14
+
15
+ def success?
16
+ @last_response && @last_response.success?
17
+ end
18
+
19
+ def persisted?
20
+ !id.nil?
21
+ end
22
+
23
+ def post(request, options = {})
24
+ @last_response = self.class.post(request, options)
25
+ end
26
+
27
+ def get(request, options = {})
28
+ @last_response = self.class.get(request, options)
29
+ end
30
+
31
+ def configuration
32
+ self.class.configuration
33
+ end
34
+
35
+ def self.underscore_attributes(attributes)
36
+ attribute_map.inject({}) do |map, keys|
37
+ qualtrics_key, ruby_key = keys[0], keys[1]
38
+ map[ruby_key] = attributes[qualtrics_key]
39
+ map
40
+ end
41
+ end
42
+
43
+ def self.post(request, options = {})
44
+ Qualtrics::Operation.new(:post, request, options).issue_request
45
+ end
46
+
47
+ def self.get(request, options = {})
48
+ Qualtrics::Operation.new(:get, request, options).issue_request
49
+ end
50
+
51
+ def self.configuration
52
+ Qualtrics.configuration
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,111 @@
1
+ require 'active_support/time'
2
+ require 'active_model/validations'
3
+
4
+ module Qualtrics
5
+ class Mailer < Entity
6
+ include ActiveSupport
7
+ include ActiveModel::Validations
8
+
9
+ attr_accessor :send_date, :from_email, :from_name, :subject, :sent_from_address
10
+ validates :send_date, presence: true
11
+ validates :from_email, presence: true
12
+ validates :from_name, presence: true
13
+ validates :subject, presence: true
14
+
15
+ QUALTRICS_POST_TIMEZONE = 'Mountain Time (US & Canada)'
16
+
17
+ def initialize(options={})
18
+ @send_date = options[:send_date] || post_time
19
+ @from_email = options[:from_email]
20
+ @from_name = options[:from_name]
21
+ @subject = options[:subject]
22
+ @sent_from_address = options[:sent_from_address] || 'noreply@qemailserver.com'
23
+ end
24
+
25
+ def send_survey_to_individual(recipient, message, survey)
26
+ return false if !valid?
27
+
28
+ response = post('sendSurveyToIndividual', attributes.merge(
29
+ {
30
+ 'RecipientID' => recipient.id,
31
+ 'MessageID' => message.id,
32
+ 'SurveyID' => survey.id,
33
+ 'MessageLibraryID' => library_id,
34
+ 'PanelID' => recipient.panel_id,
35
+ 'PanelLibraryID' => library_id
36
+ })
37
+ )
38
+
39
+ if response.success?
40
+ create_distribution(response, survey.id, message.id)
41
+ else
42
+ false
43
+ end
44
+ end
45
+
46
+ def send_survey_to_panel(panel, message, survey)
47
+ return false if !valid?
48
+
49
+ response = post('sendSurveyToPanel', attributes.merge(
50
+ {
51
+ 'PanelID' => panel.id,
52
+ 'MessageID' => message.id,
53
+ 'SurveyID' => survey.id,
54
+ 'MessageLibraryID' => library_id,
55
+ 'PanelLibraryID' => library_id
56
+ })
57
+ )
58
+
59
+ if response.success?
60
+ create_distribution(response, survey.id, message.id)
61
+ else
62
+ false
63
+ end
64
+ end
65
+
66
+ def send_reminder(distribution, message)
67
+ return false if !valid?
68
+
69
+ response = post('sendReminder', attributes.merge(
70
+ {
71
+ 'ParentEmailDistributionID' => distribution.id,
72
+ 'MessageID' => message.id,
73
+ 'LibraryID' => library_id,
74
+ })
75
+ )
76
+
77
+ if response.success?
78
+ create_distribution(response, distribution.survey_id, message.id)
79
+ else
80
+ false
81
+ end
82
+ end
83
+
84
+ def attributes
85
+ {
86
+ 'SendDate' => send_date,
87
+ 'FromEmail' => from_email,
88
+ 'FromName' => from_name,
89
+ 'Subject' => subject,
90
+ 'SentFromAddress' => sent_from_address
91
+ }
92
+ end
93
+
94
+ private
95
+ def post_time
96
+ formatted_time Time.now.utc.in_time_zone(QUALTRICS_POST_TIMEZONE)
97
+ end
98
+
99
+ def formatted_time(time)
100
+ time.strftime("%Y-%m-%d %H:%M:%S")
101
+ end
102
+
103
+ def create_distribution(response, survey_id, message_id)
104
+ Qualtrics::Distribution.new({
105
+ message_id: message_id,
106
+ survey_id: survey_id,
107
+ id: response.result['EmailDistributionID']
108
+ })
109
+ end
110
+ end
111
+ end