qrapi-wrapper 0.6.0

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 (46) hide show
  1. checksums.yaml +7 -0
  2. data/lib/qrapi.rb +79 -0
  3. data/lib/qrapi/client.rb +58 -0
  4. data/lib/qrapi/error_handling_resourceable.rb +22 -0
  5. data/lib/qrapi/mappings/contact_mapping.rb +22 -0
  6. data/lib/qrapi/mappings/distribution_mapping.rb +68 -0
  7. data/lib/qrapi/mappings/division_mapping.rb +27 -0
  8. data/lib/qrapi/mappings/error_mapping.rb +19 -0
  9. data/lib/qrapi/mappings/group_mapping.rb +27 -0
  10. data/lib/qrapi/mappings/library_message_mapping.rb +20 -0
  11. data/lib/qrapi/mappings/mailing_list_mapping.rb +20 -0
  12. data/lib/qrapi/mappings/organization_mapping.rb +19 -0
  13. data/lib/qrapi/mappings/response_export_mapping.rb +14 -0
  14. data/lib/qrapi/mappings/responses_mapping.rb +45 -0
  15. data/lib/qrapi/mappings/survey_mapping.rb +33 -0
  16. data/lib/qrapi/mappings/user_mapping.rb +40 -0
  17. data/lib/qrapi/models/base_model.rb +22 -0
  18. data/lib/qrapi/models/distribution.rb +45 -0
  19. data/lib/qrapi/models/distribution/headers.rb +27 -0
  20. data/lib/qrapi/models/distribution/message.rb +26 -0
  21. data/lib/qrapi/models/distribution/recipients.rb +26 -0
  22. data/lib/qrapi/models/distribution/survey_link.rb +26 -0
  23. data/lib/qrapi/models/division.rb +32 -0
  24. data/lib/qrapi/models/group.rb +31 -0
  25. data/lib/qrapi/models/library_message.rb +27 -0
  26. data/lib/qrapi/models/mailing_list.rb +27 -0
  27. data/lib/qrapi/models/mailing_list/contact.rb +33 -0
  28. data/lib/qrapi/models/organization.rb +29 -0
  29. data/lib/qrapi/models/response.rb +40 -0
  30. data/lib/qrapi/models/response_export.rb +71 -0
  31. data/lib/qrapi/models/survey.rb +45 -0
  32. data/lib/qrapi/models/survey/expiration.rb +25 -0
  33. data/lib/qrapi/models/user.rb +44 -0
  34. data/lib/qrapi/resources/distribution_resource.rb +47 -0
  35. data/lib/qrapi/resources/division_resource.rb +24 -0
  36. data/lib/qrapi/resources/group_resource.rb +44 -0
  37. data/lib/qrapi/resources/library_message_resource.rb +41 -0
  38. data/lib/qrapi/resources/mailing_list_resource.rb +51 -0
  39. data/lib/qrapi/resources/organization_resource.rb +12 -0
  40. data/lib/qrapi/resources/response_export_resource.rb +49 -0
  41. data/lib/qrapi/resources/response_import_resource.rb +26 -0
  42. data/lib/qrapi/resources/survey_resource.rb +27 -0
  43. data/lib/qrapi/resources/user_resource.rb +35 -0
  44. data/lib/qrapi/utils/kartograph_optional_properties.rb +21 -0
  45. data/lib/qrapi/version.rb +3 -0
  46. metadata +271 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6f55c877f28d86f3eef311c12ca12259e4cc657f9e62ace2f9276dae6f81a460
4
+ data.tar.gz: 4ae23eaeb89fb89ba8e08cb4247828c9b30326865abfdcb99bc32de6631fd5fe
5
+ SHA512:
6
+ metadata.gz: 91bfc6a270ee30f6cf7b27707271c8806994090fde5bcb5ea12b0ae169c8c3a84aec0c0554214da6277d3741eb1a5139253e860bd5aa759e13e69af7fcb7a537
7
+ data.tar.gz: eda8bb8744cd27b4e5a0ca1c740beaffb6e4d62fdea5e6d3372b08f3318c5427660e118f150f73e5245f3952c62678eea98e735ce4246823f9c775223fcd66fc
@@ -0,0 +1,79 @@
1
+ require "zip"
2
+ require "json"
3
+ require "kartograph"
4
+ require "resource_kit"
5
+ require "qrapi/version"
6
+ require "active_model"
7
+ require "active_support/all"
8
+
9
+ module QRAPI
10
+ autoload :Client, "qrapi/client"
11
+
12
+ # Models
13
+ autoload :BaseModel, "qrapi/models/base_model"
14
+ autoload :Organization, "qrapi/models/organization"
15
+ autoload :Division, "qrapi/models/division"
16
+ autoload :Group, "qrapi/models/group"
17
+ autoload :Survey, "qrapi/models/survey"
18
+ Survey.autoload :Expiration, "qrapi/models/survey/expiration"
19
+ autoload :User, "qrapi/models/user"
20
+ autoload :LibraryMessage, "qrapi/models/library_message"
21
+ autoload :Distribution, "qrapi/models/distribution"
22
+ Distribution.autoload :Headers, "qrapi/models/distribution/headers"
23
+ Distribution.autoload :Message, "qrapi/models/distribution/message"
24
+ Distribution.autoload :Recipients, "qrapi/models/distribution/recipients"
25
+ Distribution.autoload :SurveyLink, "qrapi/models/distribution/survey_link"
26
+ autoload :ResponseExport, "qrapi/models/response_export"
27
+ autoload :Response, "qrapi/models/response"
28
+ autoload :MailingList, "qrapi/models/mailing_list"
29
+ MailingList.autoload :Contact, "qrapi/models/mailing_list/contact"
30
+
31
+ # Resources
32
+ autoload :OrganizationResource, "qrapi/resources/organization_resource"
33
+ autoload :DivisionResource, "qrapi/resources/division_resource"
34
+ autoload :GroupResource, "qrapi/resources/group_resource"
35
+ autoload :SurveyResource, "qrapi/resources/survey_resource"
36
+ autoload :UserResource, "qrapi/resources/user_resource"
37
+ autoload :LibraryMessageResource, "qrapi/resources/library_message_resource"
38
+ autoload :DistributionResource, "qrapi/resources/distribution_resource"
39
+ autoload :ResponseExportResource, "qrapi/resources/response_export_resource"
40
+ autoload :ResponseImportResource, "qrapi/resources/response_import_resource"
41
+ autoload :MailingListResource, "qrapi/resources/mailing_list_resource"
42
+
43
+ # JSON Maps
44
+ autoload :OrganizationMapping, "qrapi/mappings/organization_mapping"
45
+ autoload :DivisionMapping, "qrapi/mappings/division_mapping"
46
+ autoload :GroupMapping, "qrapi/mappings/group_mapping"
47
+ autoload :SurveyMapping, "qrapi/mappings/survey_mapping"
48
+ autoload :ExpirationMapping, "qrapi/mappings/expiration_mapping"
49
+ autoload :UserMapping, "qrapi/mappings/user_mapping"
50
+ autoload :LibraryMessageMapping, "qrapi/mappings/library_message_mapping"
51
+ autoload :DistributionMapping, "qrapi/mappings/distribution_mapping"
52
+ autoload :ResponseExportMapping, "qrapi/mappings/response_export_mapping"
53
+ autoload :ResponsesMapping, "qrapi/mappings/responses_mapping"
54
+ autoload :MailingListMapping, "qrapi/mappings/mailing_list_mapping"
55
+ autoload :ContactMapping, "qrapi/mappings/contact_mapping"
56
+
57
+ # Utils
58
+ autoload :ErrorHandlingResourceable, "qrapi/error_handling_resourceable"
59
+ autoload :Kartograph, "qrapi/utils/kartograph_optional_properties"
60
+
61
+ # Errors
62
+ autoload :ErrorMapping, "qrapi/mappings/error_mapping"
63
+ Error = Class.new(StandardError)
64
+ FailedCreate = Class.new(QRAPI::Error)
65
+ FailedUpdate = Class.new(QRAPI::Error)
66
+
67
+ class RateLimitReached < QRAPI::Error
68
+ attr_accessor :reset_at
69
+ attr_writer :limit, :remaining
70
+
71
+ def limit
72
+ @limit.to_i if @limit
73
+ end
74
+
75
+ def remaining
76
+ @remaning.to_i if @remaning
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,58 @@
1
+ require "faraday"
2
+
3
+ module QRAPI
4
+ class Client
5
+ attr_reader :api_token, :data_center_id
6
+
7
+ def initialize(options = {})
8
+ @api_token = options[:api_token]
9
+ @data_center_id = options[:data_center_id]
10
+ end
11
+
12
+ def connection
13
+ Faraday.new(connection_options) do |req|
14
+ req.adapter :net_http
15
+ end
16
+ end
17
+
18
+ def self.resources
19
+ {
20
+ organization: OrganizationResource,
21
+ divisions: DivisionResource,
22
+ groups: GroupResource,
23
+ users: UserResource,
24
+ surveys: SurveyResource,
25
+ response_exports: ResponseExportResource,
26
+ response_imports: ResponseImportResource,
27
+ library_messages: LibraryMessageResource,
28
+ distributions: DistributionResource,
29
+ mailing_lists: MailingListResource
30
+ }
31
+ end
32
+
33
+ def method_missing(name, *args, &block)
34
+ if self.class.resources.keys.include?(name)
35
+ resources[name] ||= self.class.resources[name].new(connection: connection)
36
+ resources[name]
37
+ else
38
+ super
39
+ end
40
+ end
41
+
42
+ def resources
43
+ @resources ||= {}
44
+ end
45
+
46
+ private
47
+
48
+ def connection_options
49
+ {
50
+ url: "https://#{@data_center_id}.qualtrics.com",
51
+ headers: {
52
+ content_type: "application/json",
53
+ X_API_TOKEN: api_token
54
+ }
55
+ }
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,22 @@
1
+ module ErrorHandlingResourceable
2
+ def self.included(base)
3
+ base.send(:resources) do
4
+ default_handler do |response|
5
+ if (200...299).include?(response.status)
6
+ next
7
+ elsif response.status == 429
8
+ error = QRAPI::RateLimitReached.new("#{response.status}: #{response.body}")
9
+ error.limit = response.headers["RateLimit-Limit"]
10
+ error.remaining = response.headers["RateLimit-Remaining"]
11
+ error.reset_at = response.headers["RateLimit-Reset"]
12
+ raise error
13
+ else
14
+ body = JSON.parse(response.body)
15
+ error_message = body["meta"]["error"]["errorMessage"]
16
+ error_code = body["meta"]["error"]["errorCode"]
17
+ raise QRAPI::Error.new("Status: #{response.status} Error: #{error_code} - #{error_message}")
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ module QRAPI
2
+ class ContactMapping
3
+ include Kartograph::DSL
4
+
5
+ kartograph do
6
+ mapping MailingList::Contact
7
+ root_key plural: "elements", scopes: [:read]
8
+
9
+ property :id, scopes: [:read]
10
+
11
+ scoped :read, :update do
12
+ property :first_name, key: "firstName", optional: true
13
+ property :last_name, key: "lastName", optional: true
14
+ property :email, optional: true
15
+ property :external_data_reference, key: "externalDataReference", optional: true
16
+ property :language, optional: true
17
+ property :embedded_data, key: "embeddedData", optional: true
18
+ property :unsubscribed, optional: true
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,68 @@
1
+ module QRAPI
2
+ class DistributionMapping
3
+ include Kartograph::DSL
4
+
5
+ kartograph do
6
+ mapping Distribution
7
+ root_key singular: "result", plural: "elements", scopes: [:read]
8
+
9
+ property :send_date, scopes: [:read, :create, :create_child], key: "sendDate"
10
+
11
+ property :recipients, scopes: [:read, :create] do
12
+ mapping Distribution::Recipients
13
+
14
+ property :mailing_list_id, scopes: [:read, :create], key: "mailingListId"
15
+ property :contact_id, scopes: [:read, :create], key: "contactId", optional: true
16
+ end
17
+
18
+ property :headers, scopes: [:read, :create, :create_child] do
19
+ mapping Distribution::Headers
20
+
21
+ property :from_email, scopes: [:read, :create, :create_child], key: "fromEmail"
22
+ property :from_name, scopes: [:read, :create, :create_child], key: "fromName"
23
+ property :reply_to_email, scopes: [:read, :create, :create_child], key: "replyToEmail"
24
+ property :subject, scopes: [:read, :create, :create_child]
25
+ end
26
+
27
+ property :message, scopes: [:read, :create], optional: true do
28
+ mapping Distribution::Message
29
+
30
+ property :message_id, scopes: [:read, :create], key: "messageId"
31
+ property :library_id, scopes: [:read, :create], key: "libraryId"
32
+ property :message_text, scopes: [:read, :create], key: "messageText"
33
+ end
34
+
35
+ property :survey_link, scopes: [:read, :create], optional: true, key: "surveyLink" do
36
+ mapping Distribution::SurveyLink
37
+
38
+ property :survey_id, scopes: [:read, :create], key: "surveyId"
39
+ property :expiration_date, scopes: [:read, :create], key: "expirationDate"
40
+ property :type, scopes: [:read, :create]
41
+ end
42
+
43
+ scoped :read do
44
+ property :id
45
+ property :parent_distribution_id, key: "parentDistributionId"
46
+ property :owner_id, key: "ownerId"
47
+ property :organization_id, key: "organizationId"
48
+ property :request_status, key: "requestStatus"
49
+ property :request_type, key: "requestType"
50
+ property :created_date, key: "createdDate"
51
+ property :modified_date, key: "modifiedDate"
52
+ property :stats
53
+ end
54
+
55
+ scoped :create_child do
56
+ property :message do
57
+ mapping Distribution::Message
58
+
59
+ scoped :create_child do
60
+ property :message_id, key: "messageId"
61
+ property :library_id, key: "libraryId"
62
+ property :message_text, key: "messageText"
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,27 @@
1
+ module QRAPI
2
+ class DivisionMapping
3
+ include Kartograph::DSL
4
+
5
+ kartograph do
6
+ mapping Division
7
+ root_key singular: "result", scopes: [:read]
8
+
9
+ property :name, scopes: [:read, :update], optional: true
10
+ property :status, scopes: [:read, :update], optional: true
11
+ # property :permissions, scopes: [:read, :create, :update], optional: true
12
+
13
+ scoped :read do
14
+ property :id
15
+ property :organization_id, key: "organizationId"
16
+ property :creation_date, key: "creationDate"
17
+ property :creator_id, key: "creatorId"
18
+ property :response_counts, key: "responseCounts"
19
+ end
20
+
21
+ scoped :create do
22
+ property :name
23
+ property :division_admins, key: "divisionAdmins", optional: true
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ module QRAPI
2
+ class ErrorMapping
3
+ Error = Struct.new(:message, :id)
4
+
5
+ include Kartograph::DSL
6
+
7
+ kartograph do
8
+ mapping Error
9
+
10
+ property :id, scopes: [:read]
11
+ property :message, scopes: [:read]
12
+ end
13
+
14
+ def self.fail_with(klass, content)
15
+ error = extract_single(content, :read)
16
+ raise klass, error.message
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ module QRAPI
2
+ class GroupMapping
3
+ include Kartograph::DSL
4
+
5
+ kartograph do
6
+ mapping Group
7
+ root_key singular: "result", plural: "elements", scopes: [:read]
8
+
9
+ property :type, scopes: [:read, :create]
10
+ property :name, scopes: [:read, :create]
11
+ property :division_id, scopes: [:read, :update], key: "divisionId", optional: true
12
+
13
+ scoped :read do
14
+ property :id
15
+ property :organization_id, key: "organizationId"
16
+ property :all_users, key: "allUsers"
17
+ property :creation_date, key: "creationDate"
18
+ property :creator_id, key: "creatorId"
19
+ end
20
+
21
+ scoped :update do
22
+ property :type, optional: true
23
+ property :name, optional: true
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,20 @@
1
+ module QRAPI
2
+ class LibraryMessageMapping
3
+ include Kartograph::DSL
4
+
5
+ kartograph do
6
+ mapping LibraryMessage
7
+ root_key singular: "result", plural: "elements", scopes: [:read]
8
+
9
+ property :id, scopes: [:read]
10
+ property :category, scopes: [:read, :create]
11
+ property :messages, scopes: [:read, :update], optional: true
12
+ property :description, scopes: [:read, :update], optional: true
13
+
14
+ scoped :create do
15
+ property :description
16
+ property :messages
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module QRAPI
2
+ class MailingListMapping
3
+ include Kartograph::DSL
4
+
5
+ kartograph do
6
+ mapping MailingList
7
+ root_key singular: "result", plural: "elements", scopes: [:read]
8
+
9
+ property :id, scopes: [:read]
10
+ property :name, scopes: [:read, :create]
11
+ property :library_id, scopes: [:read, :create], key: "libraryId"
12
+ property :category, scopes: [:read, :create, :update], optional: true
13
+
14
+ scoped :update do
15
+ property :name, optional: true
16
+ property :library_id, key: "libraryId", optional: true
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ module QRAPI
2
+ class OrganizationMapping
3
+ include Kartograph::DSL
4
+
5
+ kartograph do
6
+ mapping Organization
7
+ root_key singular: "result", scopes: [:read]
8
+
9
+ scoped :read do
10
+ property :id
11
+ property :name
12
+ property :base_url
13
+ property :type
14
+ property :status
15
+ property :stats
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ module QRAPI
2
+ class ResponseExportMapping
3
+ include Kartograph::DSL
4
+
5
+ kartograph do
6
+ mapping ResponseExport
7
+ root_key singular: "result", scopes: [:read]
8
+
9
+ scoped :read do
10
+ property :percent_complete, key: "percentComplete"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,45 @@
1
+ module QRAPI
2
+ class ResponsesMapping
3
+ # Maps each of the responses to a QRAPI::Response model
4
+ #
5
+ # @return [QRAPI::Response]
6
+ def self.from_json_or_xml(serialized_response, f_type)
7
+ case f_type
8
+ when :json
9
+ responses_hash = JSON.parse(serialized_response)
10
+ unmapped_responses = responses_hash["responses"]
11
+ when :xml
12
+ responses_hash = Hash.from_xml(serialized_response)
13
+ unmapped_responses = responses_hash["xml"]["Response"]
14
+ end
15
+
16
+ responses = []
17
+ unmapped_responses.each do |response|
18
+ r = Response.new
19
+ r.id = response["ResponseID"]
20
+ r.response_set = response["ResponseSet"]
21
+ r.ip_address = response["IPAddress"]
22
+ r.start_date = response["StartDate"]
23
+ r.end_date = response["EndDate"]
24
+ r.last_name = response["RecipientLastName"]
25
+ r.first_name = response["RecipientFirstName"]
26
+ r.email = response["RecipientEmail"]
27
+ r.external_data_reference = response["ExternalDataReference"]
28
+ r.finished = response["Finished"]
29
+ r.status = response["Status"]
30
+ r.location_latitude = response["LocationLatitude"]
31
+ r.location_longitude = response["LocationLongitude"]
32
+ r.location_accuracy = response["LocationAccuracy"]
33
+
34
+ r.questions = {}
35
+ response.keys.grep(/Q([0-9xy_]+)/).each do |key|
36
+ r.questions[key] = response[key]
37
+ end
38
+
39
+ responses << r
40
+ end
41
+
42
+ responses
43
+ end
44
+ end
45
+ end