qualtrics 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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