qualtrics_api 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,3 @@
1
+ module QualtricsAPI
2
+ URL = "https://co1.qualtrics.com:443/API/v1/"
3
+ end
@@ -0,0 +1,3 @@
1
+ module QualtricsAPI
2
+ VERSION = "0.0.1"
3
+ 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