qualtrics_api 0.0.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.
- checksums.yaml +7 -0
- data/.gitignore +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +141 -0
- data/Rakefile +7 -0
- data/fixtures/vcr_cassettes/response_export_start_success.yml +32 -0
- data/fixtures/vcr_cassettes/response_export_update_success.yml +61 -0
- data/fixtures/vcr_cassettes/survey_collection_fetch_fail.yml +33 -0
- data/fixtures/vcr_cassettes/survey_collection_fetch_sucess.yml +33 -0
- data/fixtures/vcr_cassettes/survey_collection_fetch_with_scopeId_success.yml +33 -0
- data/lib/qualtrics_api.rb +23 -0
- data/lib/qualtrics_api/client.rb +32 -0
- data/lib/qualtrics_api/request_error_handler.rb +37 -0
- data/lib/qualtrics_api/response_export.rb +40 -0
- data/lib/qualtrics_api/response_export_collection.rb +24 -0
- data/lib/qualtrics_api/services/response_export_service.rb +90 -0
- data/lib/qualtrics_api/survey.rb +29 -0
- data/lib/qualtrics_api/survey_collection.rb +64 -0
- data/lib/qualtrics_api/url.rb +3 -0
- data/lib/qualtrics_api/version.rb +3 -0
- data/qualtrics_api.gemspec +30 -0
- data/spec/lib/client_spec.rb +47 -0
- data/spec/lib/response_export_collection_spec.rb +33 -0
- data/spec/lib/response_export_spec.rb +94 -0
- data/spec/lib/services/response_export_service_spec.rb +110 -0
- data/spec/lib/survey_collection_spec.rb +106 -0
- data/spec/lib/survey_spec.rb +60 -0
- data/spec/qualtrics_api_spec.rb +14 -0
- data/spec/spec_helper.rb +9 -0
- metadata +167 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "faraday_middleware"
|
3
|
+
|
4
|
+
require "qualtrics_api/version"
|
5
|
+
require "qualtrics_api/url"
|
6
|
+
|
7
|
+
require "qualtrics_api/request_error_handler"
|
8
|
+
|
9
|
+
require "qualtrics_api/client"
|
10
|
+
require "qualtrics_api/survey"
|
11
|
+
require "qualtrics_api/survey_collection"
|
12
|
+
require "qualtrics_api/response_export"
|
13
|
+
require "qualtrics_api/response_export_collection"
|
14
|
+
|
15
|
+
require "qualtrics_api/services/response_export_service"
|
16
|
+
|
17
|
+
module QualtricsAPI
|
18
|
+
|
19
|
+
def self.new(token)
|
20
|
+
Client.new(api_token: token)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module QualtricsAPI
|
2
|
+
|
3
|
+
class Client
|
4
|
+
attr_reader :api_token
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
@api_token = options[:api_token]
|
8
|
+
end
|
9
|
+
|
10
|
+
def surveys(options = {})
|
11
|
+
@surveys ||= QualtricsAPI::SurveyCollection.new options.merge({ connection: connection })
|
12
|
+
end
|
13
|
+
|
14
|
+
def response_exports(options = {})
|
15
|
+
@response_exports ||= QualtricsAPI::ResponseExportCollection.new options.merge({ connection: connection })
|
16
|
+
end
|
17
|
+
|
18
|
+
def connection
|
19
|
+
@conn ||= Faraday.new(url: QualtricsAPI::URL,
|
20
|
+
params: { apiToken: @api_token }) do |faraday|
|
21
|
+
faraday.request :json
|
22
|
+
faraday.response :json, :content_type => /\bjson$/
|
23
|
+
|
24
|
+
faraday.use FaradayMiddleware::FollowRedirects
|
25
|
+
faraday.use QualtricsAPI::RequestErrorHandler
|
26
|
+
|
27
|
+
faraday.adapter Faraday.default_adapter
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module QualtricsAPI
|
2
|
+
|
3
|
+
class RequestErrorHandler < Faraday::Response::Middleware
|
4
|
+
|
5
|
+
def on_complete(env)
|
6
|
+
case env[:status]
|
7
|
+
when 404
|
8
|
+
raise NotFoundError, "Not Found"
|
9
|
+
when 400
|
10
|
+
raise BadRequestError, error_message(JSON.parse(env[:body]))
|
11
|
+
when 401
|
12
|
+
raise UnauthorizedError, error_message(JSON.parse(env[:body]))
|
13
|
+
when 500
|
14
|
+
raise InternalServerError, error_message(JSON.parse(env[:body]))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def error_message(response)
|
21
|
+
meta = response["meta"]
|
22
|
+
[ "[",
|
23
|
+
meta["status"], " - ",
|
24
|
+
meta["qualtricsErrorCode"] || meta["internalErrorCode"],
|
25
|
+
"] ",
|
26
|
+
meta["errorMessage"]
|
27
|
+
].join
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class NotFoundError < StandardError; end
|
33
|
+
class BadRequestError < StandardError; end
|
34
|
+
class UnauthorizedError < StandardError; end
|
35
|
+
class InternalServerError < StandardError; end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module QualtricsAPI
|
2
|
+
|
3
|
+
class ResponseExport
|
4
|
+
|
5
|
+
attr_reader :id
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@conn = options[:connection]
|
9
|
+
@id = options[:id]
|
10
|
+
end
|
11
|
+
|
12
|
+
def update_status
|
13
|
+
res = @conn.get('surveys/responseExports/' + @id).body["result"]
|
14
|
+
@export_progress = res["percentComplete"]
|
15
|
+
@file_url = res["fileUrl"]
|
16
|
+
@completed = true if @export_progress == 100.0
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def status
|
21
|
+
update_status unless completed?
|
22
|
+
"#{@export_progress}%"
|
23
|
+
end
|
24
|
+
|
25
|
+
def percent_completed
|
26
|
+
update_status unless completed?
|
27
|
+
@export_progress
|
28
|
+
end
|
29
|
+
|
30
|
+
def completed?
|
31
|
+
@completed == true
|
32
|
+
end
|
33
|
+
|
34
|
+
def file_url
|
35
|
+
update_status unless completed?
|
36
|
+
@file_url
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module QualtricsAPI
|
2
|
+
class ResponseExportCollection
|
3
|
+
extend Forwardable
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
attr_reader :all
|
7
|
+
|
8
|
+
def_delegator :all, :each
|
9
|
+
def_delegator :all, :size
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
@conn = options[:connection]
|
13
|
+
@all = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def [](export_id); find(export_id); end
|
17
|
+
def find(export_id)
|
18
|
+
@all.select do |response_export|
|
19
|
+
response_export.id == export_id
|
20
|
+
end.first || QualtricsAPI::ResponseExport.new(:id => export_id , connection: @conn)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module QualtricsAPI
|
2
|
+
module Services
|
3
|
+
class ResponseExportService
|
4
|
+
attr_reader :survey_id,
|
5
|
+
:response_set_id,
|
6
|
+
:file_type,
|
7
|
+
:last_response_id,
|
8
|
+
:start_date,
|
9
|
+
:end_date,
|
10
|
+
:limit,
|
11
|
+
:included_question_ids,
|
12
|
+
:max_rows,
|
13
|
+
:use_labels,
|
14
|
+
:decimal_format,
|
15
|
+
:seen_unanswered_recode,
|
16
|
+
:use_local_time,
|
17
|
+
:spss_string_length,
|
18
|
+
:result
|
19
|
+
|
20
|
+
def initialize(options = {})
|
21
|
+
@conn = options[:connection]
|
22
|
+
@survey_id = options[:survey_id]
|
23
|
+
@response_set_id = options[:response_set_id]
|
24
|
+
@file_type = options[:file_type] || 'CSV'
|
25
|
+
@last_response_id = options[:last_response_id]
|
26
|
+
@start_date = options[:start_date]
|
27
|
+
@end_date = options[:end_date]
|
28
|
+
@limit = options[:limit]
|
29
|
+
@included_question_ids = options[:included_question_ids]
|
30
|
+
@max_rows = options[:max_rows]
|
31
|
+
@use_labels = options.has_key?(:use_labels) ? options[:use_labels] : false
|
32
|
+
@decimal_format = options[:decimal_format] || '.'
|
33
|
+
@seen_unanswered_recode = options[:seen_unanswered_recode]
|
34
|
+
@use_local_time = options.has_key?(:use_local_time) ? options[:use_local_time] : false
|
35
|
+
@spss_string_length = options[:spss_string_length]
|
36
|
+
@id = options[:id]
|
37
|
+
end
|
38
|
+
|
39
|
+
def start
|
40
|
+
response = @conn.get("surveys/#{@survey_id}/responseExports", export_params)
|
41
|
+
export_id = response.body["result"]["exportStatus"].split('/').last
|
42
|
+
@result = ResponseExport.new(id: export_id, connection: @conn)
|
43
|
+
end
|
44
|
+
|
45
|
+
def export_configurations
|
46
|
+
{
|
47
|
+
response_set_id: @response_set_id,
|
48
|
+
file_type: @file_type,
|
49
|
+
last_response_id: @last_response_id,
|
50
|
+
start_date: @start_date,
|
51
|
+
end_date: @end_date,
|
52
|
+
limit: @limit,
|
53
|
+
included_question_ids: @included_question_ids,
|
54
|
+
max_rows: @max_rows,
|
55
|
+
use_labels: @use_labels,
|
56
|
+
decimal_format: @decimal_format,
|
57
|
+
seen_unanswered_recode: @seen_unanswered_recode,
|
58
|
+
use_local_time: @use_local_time,
|
59
|
+
spss_string_length: @spss_string_length
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def param_mappings
|
66
|
+
{
|
67
|
+
response_set_id: "responseSetId",
|
68
|
+
file_type: "fileType",
|
69
|
+
last_response_id: "lastResponseId",
|
70
|
+
start_date: "startDate",
|
71
|
+
end_date: "endDate",
|
72
|
+
limit: "limit",
|
73
|
+
included_question_ids: "includedQuestionIds",
|
74
|
+
max_rows: "maxRows",
|
75
|
+
use_labels: "useLabels",
|
76
|
+
decimal_format: "decimalFormat",
|
77
|
+
seen_unanswered_recode: "seenUnansweredRecode",
|
78
|
+
use_local_time: "useLocalTime",
|
79
|
+
spss_string_length: "spssStringLength"
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
def export_params
|
84
|
+
export_configurations.map do |config_key, value|
|
85
|
+
[param_mappings[config_key], value] unless value.nil? || value.to_s.empty?
|
86
|
+
end.compact.to_h
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module QualtricsAPI
|
2
|
+
|
3
|
+
class Survey
|
4
|
+
attr_accessor :id, :name, :owner_id, :last_modified, :status
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
attributes_mappings.each do |key, qualtrics_key|
|
8
|
+
instance_variable_set "@#{key}", options[qualtrics_key]
|
9
|
+
end
|
10
|
+
@conn = options[:connection]
|
11
|
+
end
|
12
|
+
|
13
|
+
def export_responses(export_options = {})
|
14
|
+
QualtricsAPI::Services::ResponseExportService.new(export_options.merge(survey_id: id, connection: @conn))
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def attributes_mappings
|
20
|
+
{
|
21
|
+
:id => "id",
|
22
|
+
:name => "name",
|
23
|
+
:owner_id => "ownerId",
|
24
|
+
:last_modified => "lastModified",
|
25
|
+
:status => "status"
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module QualtricsAPI
|
2
|
+
|
3
|
+
class SurveyCollection
|
4
|
+
extend Forwardable
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
attr_accessor :scope_id
|
8
|
+
attr_reader :all
|
9
|
+
|
10
|
+
def_delegator :all, :each
|
11
|
+
def_delegator :all, :size
|
12
|
+
|
13
|
+
def initialize(options = {})
|
14
|
+
@conn = options[:connection]
|
15
|
+
@scope_id = options[:scope_id]
|
16
|
+
@all = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def fetch(options = {})
|
20
|
+
@all = []
|
21
|
+
update_query_attributes(options)
|
22
|
+
parse_fetch_response(@conn.get('surveys', query_params))
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def query_attributes
|
27
|
+
{
|
28
|
+
:scope_id => @scope_id
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def update_query_attributes(new_attributes = {})
|
33
|
+
@scope_id = new_attributes[:scope_id] if new_attributes.has_key? :scope_id
|
34
|
+
end
|
35
|
+
|
36
|
+
def [](survey_id); find(survey_id); end
|
37
|
+
def find(survey_id)
|
38
|
+
@all.select do |survey|
|
39
|
+
survey.id == survey_id
|
40
|
+
end.first || QualtricsAPI::Survey.new("id" => survey_id , connection: @conn)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def attributes_mapping
|
46
|
+
{
|
47
|
+
:scope_id => "scopeId"
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def query_params
|
52
|
+
query_attributes.map do |k, v|
|
53
|
+
[attributes_mapping[k], v] unless v.nil? || v.to_s.empty?
|
54
|
+
end.compact.to_h
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse_fetch_response(response)
|
58
|
+
@all = response.body["result"].map do |result|
|
59
|
+
QualtricsAPI::Survey.new result.merge(connection: @conn)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
require 'qualtrics_api/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "qualtrics_api"
|
9
|
+
spec.version = QualtricsAPI::VERSION
|
10
|
+
spec.authors = ["Yurui Zhang"]
|
11
|
+
spec.email = ["yuruiology@gmail.com"]
|
12
|
+
spec.summary = %q{A Ruby wrapper for Qualtrics REST API v3.0}
|
13
|
+
spec.description = %q{A Ruby wrapper for Qualtrics REST API version 3.0.
|
14
|
+
See https://co1.qualtrics.com/APIDocs/ for API documents.}
|
15
|
+
spec.homepage = ""
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0")
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_dependency "faraday", "~> 0.9.1"
|
24
|
+
spec.add_dependency "faraday_middleware", "~> 0.9.1"
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
spec.add_development_dependency "rspec", "~> 3.2.0"
|
29
|
+
spec.add_development_dependency "vcr", "~> 2.9.3"
|
30
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe QualtricsAPI::Client do
|
4
|
+
|
5
|
+
subject { QualtricsAPI::Client.new(:api_token => "someToken") }
|
6
|
+
|
7
|
+
it "has an api token" do
|
8
|
+
expect(subject.api_token).to eq "someToken"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "does not allow changing the token once initialized" do
|
12
|
+
expect(subject).to_not respond_to(:api_token=)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#response_exports" do
|
16
|
+
it "returns a ResponseExportCollection" do
|
17
|
+
expect(subject.response_exports).to be_a QualtricsAPI::ResponseExportCollection
|
18
|
+
end
|
19
|
+
|
20
|
+
it "sets connection" do
|
21
|
+
expect(subject.surveys.instance_variable_get(:@conn)).to eq subject.connection
|
22
|
+
end
|
23
|
+
|
24
|
+
it "caches the collection" do
|
25
|
+
expect(subject.response_exports.object_id).to eq subject.response_exports.object_id
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#surveys" do
|
30
|
+
it "returns a SurveyCollection" do
|
31
|
+
expect(subject.surveys).to be_a QualtricsAPI::SurveyCollection
|
32
|
+
end
|
33
|
+
|
34
|
+
it "sets connection" do
|
35
|
+
expect(subject.surveys.instance_variable_get(:@conn)).to eq subject.connection
|
36
|
+
end
|
37
|
+
|
38
|
+
it "assigns scope_id if passed" do
|
39
|
+
expect(subject.surveys(:scope_id => "someId").scope_id).to eq "someId"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "caches the surveys" do
|
43
|
+
expect(subject.surveys.object_id).to eq subject.surveys.object_id
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe QualtricsAPI::ResponseExportCollection do
|
4
|
+
let(:connection) { double('connection') }
|
5
|
+
|
6
|
+
subject { described_class.new connection: connection }
|
7
|
+
|
8
|
+
it "has no @all when initialized" do
|
9
|
+
expect(subject.all).to eq []
|
10
|
+
end
|
11
|
+
|
12
|
+
it "takes a connection" do
|
13
|
+
expect(subject.instance_variable_get(:@conn)).to eq connection
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#find, #[]" do
|
17
|
+
let(:export_1) { QualtricsAPI::ResponseExport.new :id => "export1" }
|
18
|
+
let(:export_2) { QualtricsAPI::ResponseExport.new :id => "export2" }
|
19
|
+
|
20
|
+
it "finds the export by id" do
|
21
|
+
subject.instance_variable_set :@all, [export_1, export_2]
|
22
|
+
expect(subject.find("export1")).to eq export_1
|
23
|
+
expect(subject["export2"]).to eq export_2
|
24
|
+
end
|
25
|
+
|
26
|
+
it "returns a new survey with the id" do
|
27
|
+
sut = subject["eee 3"]
|
28
|
+
expect(sut).to be_a QualtricsAPI::ResponseExport
|
29
|
+
expect(sut.id).to eq "eee 3"
|
30
|
+
expect(sut.instance_variable_get(:@conn)).to eq connection
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|