toccatore 0.3.9 → 0.4.15

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 (78) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile.lock +76 -54
  3. data/README.md +1 -1
  4. data/lib/toccatore/base.rb +15 -4
  5. data/lib/toccatore/cli.rb +12 -0
  6. data/lib/toccatore/datacite_related.rb +18 -3
  7. data/lib/toccatore/orcid_update.rb +6 -2
  8. data/lib/toccatore/queue.rb +56 -0
  9. data/lib/toccatore/usage_update.rb +183 -0
  10. data/lib/toccatore/version.rb +1 -1
  11. data/lib/toccatore.rb +2 -0
  12. data/spec/base_spec.rb +4 -4
  13. data/spec/cli_spec.rb +36 -3
  14. data/spec/datacite_related_spec.rb +10 -10
  15. data/spec/factories/default.rb +22 -0
  16. data/spec/fixtures/event_data_resp_1 +2 -0
  17. data/spec/fixtures/event_data_resp_2 +4 -0
  18. data/spec/fixtures/events_empty.json +33 -0
  19. data/spec/fixtures/usage_event.json +1 -0
  20. data/spec/fixtures/usage_event_fail.json +17 -0
  21. data/spec/fixtures/usage_events.json +63 -0
  22. data/spec/fixtures/usage_update.json +101 -0
  23. data/spec/fixtures/usage_update_1.json +36738 -0
  24. data/spec/fixtures/usage_update_2.json +171 -0
  25. data/spec/fixtures/usage_update_3.json +176 -0
  26. data/spec/fixtures/usage_update_4.json +101 -0
  27. data/spec/fixtures/usage_update_nil.json +6 -0
  28. data/spec/fixtures/vcr_cassettes/Toccatore_Base/get_doi_ra/crossref.yml +21 -45
  29. data/spec/fixtures/vcr_cassettes/Toccatore_Base/get_doi_ra/datacite.yml +23 -47
  30. data/spec/fixtures/vcr_cassettes/Toccatore_Base/send_notification_to_slack/datacite_related.yml +14 -12
  31. data/spec/fixtures/vcr_cassettes/Toccatore_Base/send_notification_to_slack/datacite_related_no_works.yml +15 -13
  32. data/spec/fixtures/vcr_cassettes/Toccatore_Base/send_notification_to_slack/orcid_update.yml +14 -12
  33. data/spec/fixtures/vcr_cassettes/Toccatore_Base/send_notification_to_slack/orcid_update_no_works.yml +15 -13
  34. data/spec/fixtures/vcr_cassettes/Toccatore_CLI/datacite_related/should_fail.yml +345 -852
  35. data/spec/fixtures/vcr_cassettes/Toccatore_CLI/datacite_related/should_query_by_DOI.yml +327 -409
  36. data/spec/fixtures/vcr_cassettes/Toccatore_CLI/datacite_related/should_query_by_related_identifier.yml +140 -117
  37. data/spec/fixtures/vcr_cassettes/Toccatore_CLI/datacite_related/should_succeed.yml +1267 -2068
  38. data/spec/fixtures/vcr_cassettes/Toccatore_CLI/datacite_related/should_succeed_with_no_works.yml +31 -25
  39. data/spec/fixtures/vcr_cassettes/Toccatore_CLI/orcid_update/should_fail.yml +47 -39
  40. data/spec/fixtures/vcr_cassettes/Toccatore_CLI/orcid_update/should_query_by_DOI.yml +673 -855
  41. data/spec/fixtures/vcr_cassettes/Toccatore_CLI/orcid_update/should_query_by_ORCID_ID.yml +1885 -2419
  42. data/spec/fixtures/vcr_cassettes/Toccatore_CLI/orcid_update/should_succeed.yml +1555 -1991
  43. data/spec/fixtures/vcr_cassettes/Toccatore_CLI/orcid_update/should_succeed_with_no_works.yml +31 -27
  44. data/spec/fixtures/vcr_cassettes/Toccatore_CLI/usage_update/no_reports_in_the_queue/should_succeed_with_no_works.yml +196 -0
  45. data/spec/fixtures/vcr_cassettes/Toccatore_DataciteRelated/get_data/should_allow_queries_by_DOI_of_the_Datacite_Metadata_Search_API.yml +16 -12
  46. data/spec/fixtures/vcr_cassettes/Toccatore_DataciteRelated/get_data/should_allow_queries_by_related_identifier_of_the_Datacite_Metadata_Search_API.yml +17 -13
  47. data/spec/fixtures/vcr_cassettes/Toccatore_DataciteRelated/get_data/should_report_if_there_are_no_works_returned_by_the_Datacite_Metadata_Search_API.yml +16 -12
  48. data/spec/fixtures/vcr_cassettes/Toccatore_DataciteRelated/get_data/should_report_if_there_are_works_returned_by_the_Datacite_Metadata_Search_API.yml +16 -14
  49. data/spec/fixtures/vcr_cassettes/Toccatore_DataciteRelated/get_total/with_no_works.yml +15 -11
  50. data/spec/fixtures/vcr_cassettes/Toccatore_DataciteRelated/get_total/with_works.yml +16 -12
  51. data/spec/fixtures/vcr_cassettes/Toccatore_DataciteRelated/parse_data/should_report_if_there_are_works_returned_by_the_Datacite_Metadata_Search_API.yml +437 -869
  52. data/spec/fixtures/vcr_cassettes/Toccatore_DataciteRelated/push_data/should_report_if_there_are_works_returned_by_the_Datacite_Metadata_Search_API.yml +1240 -1662
  53. data/spec/fixtures/vcr_cassettes/Toccatore_DataciteRelated/push_data/should_work_with_DataCite_Event_Data.yml +4026 -6556
  54. data/spec/fixtures/vcr_cassettes/Toccatore_OrcidUpdate/get_data/should_allow_queries_by_DOI_of_the_Datacite_Metadata_Search_API.yml +15 -13
  55. data/spec/fixtures/vcr_cassettes/Toccatore_OrcidUpdate/get_data/should_allow_queries_by_ORCID_ID_of_the_Datacite_Metadata_Search_API.yml +15 -11
  56. data/spec/fixtures/vcr_cassettes/Toccatore_OrcidUpdate/get_data/should_report_if_there_are_no_works_returned_by_the_Datacite_Metadata_Search_API.yml +15 -11
  57. data/spec/fixtures/vcr_cassettes/Toccatore_OrcidUpdate/get_data/should_report_if_there_are_works_returned_by_the_Datacite_Metadata_Search_API.yml +15 -13
  58. data/spec/fixtures/vcr_cassettes/Toccatore_OrcidUpdate/get_total/with_no_works.yml +15 -13
  59. data/spec/fixtures/vcr_cassettes/Toccatore_OrcidUpdate/get_total/with_works.yml +15 -13
  60. data/spec/fixtures/vcr_cassettes/Toccatore_OrcidUpdate/push_data/should_delete_claims.yml +25 -32
  61. data/spec/fixtures/vcr_cassettes/Toccatore_OrcidUpdate/push_data/should_report_if_there_are_works_returned_by_the_Datacite_Metadata_Search_API.yml +1347 -1791
  62. data/spec/fixtures/vcr_cassettes/Toccatore_OrcidUpdate/queue_jobs/should_report_if_there_are_no_works_returned_by_the_Datacite_Metadata_Search_API.yml +14 -10
  63. data/spec/fixtures/vcr_cassettes/Toccatore_OrcidUpdate/queue_jobs/should_report_if_there_are_works_returned_by_the_Datacite_Metadata_Search_API.yml +29 -25
  64. data/spec/fixtures/vcr_cassettes/Toccatore_UsageUpdate/get_data/when_there_are_messages/should_return_the_data_for_one_message.yml +73 -0
  65. data/spec/fixtures/vcr_cassettes/Toccatore_UsageUpdate/get_data/when_there_is_ONE_message/should_return_the_data_for_one_message.yml +73 -0
  66. data/spec/fixtures/vcr_cassettes/Toccatore_UsageUpdate/get_message/should_return_no_meessage_when_the_queue_is_empty.yml +95 -0
  67. data/spec/fixtures/vcr_cassettes/Toccatore_UsageUpdate/get_message/should_return_one_message_when_there_are_multiple_messages.yml +95 -0
  68. data/spec/fixtures/vcr_cassettes/Toccatore_UsageUpdate/get_total/when_is_working_with_AWS.yml +187 -0
  69. data/spec/fixtures/vcr_cassettes/Toccatore_UsageUpdate/push_data/should_fail_if_format_of_the_event_is_empty.yml +169 -0
  70. data/spec/fixtures/vcr_cassettes/Toccatore_UsageUpdate/push_data/should_fail_if_format_of_the_event_is_wrong.yml +667 -0
  71. data/spec/fixtures/vcr_cassettes/Toccatore_UsageUpdate/push_data/should_work_with_a_single_item.yml +169 -0
  72. data/spec/fixtures/vcr_cassettes/Toccatore_UsageUpdate/queue_url/should_return_always_correct_queue_url.yml +49 -0
  73. data/spec/orcid_update_spec.rb +1 -1
  74. data/spec/queue_spec.rb +47 -0
  75. data/spec/spec_helper.rb +23 -1
  76. data/spec/usage_update_spec.rb +146 -0
  77. data/toccatore.gemspec +11 -5
  78. metadata +109 -26
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e3f403a9be0abc0a29474ba5afe14da96d2fac0e
4
- data.tar.gz: 7d518eaf6d26315f8291b7c71e92a66c0f2a6cae
2
+ SHA256:
3
+ metadata.gz: 56e3f7a50bedf097a157e0eab460c4131df5541a8ccb64c05a344ce90464060d
4
+ data.tar.gz: b01a010b2ac258c47c2cb705a4d122bb27f3a342dd838cdbab9c832dac66a563
5
5
  SHA512:
6
- metadata.gz: bfa83ed964ebd3fdb4cfb6bbf6ecec63477c1d1f3917cecb1040840584468af911add82a09f8c6d079ab814caa8091e3441489dd22ecfab2b67ef24bb98679db
7
- data.tar.gz: b8dd0cdd1975f5a0bd1508e6e8711d4e6e1538a46a8cd4b1fad0ec6a2837bb2c61ba54595f370a7c5d25b1153a5b36b707f7e559dd0b9ebf954db32f77518dc2
6
+ metadata.gz: 43afaa44061b2488a5e5c0a9f243f8bd951d63f3742854c7c65522d78783b7dae2d2959bb33c818462f6e509d0da532686b9bbb1b807a7d989beeea2bbe558cf
7
+ data.tar.gz: 4ea332dd543c5b933a31dd3736cc87e54bf5dd967e010059e0b1975c4ad045b38536bfceef217f41a9d7db4d66602258405fae6219fbae83cb0c6eaedf2b21d9
data/Gemfile.lock CHANGED
@@ -1,11 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- toccatore (0.3.9)
5
- activesupport (~> 4.2, >= 4.2.5)
4
+ toccatore (0.4.15)
5
+ activesupport (>= 4.2.5, < 6)
6
+ aws-sdk-sqs
6
7
  dotenv (~> 2.1, >= 2.1.1)
8
+ factory_bot
7
9
  gender_detector (~> 1.0)
8
- maremma (~> 3.5)
10
+ maremma (>= 3.5.7, < 5)
9
11
  namae (~> 0.11.0)
10
12
  slack-notifier (~> 2.1)
11
13
  thor (~> 0.19)
@@ -13,82 +15,100 @@ PATH
13
15
  GEM
14
16
  remote: https://rubygems.org/
15
17
  specs:
16
- activesupport (4.2.9)
17
- i18n (~> 0.7)
18
+ activesupport (5.2.1)
19
+ concurrent-ruby (~> 1.0, >= 1.0.2)
20
+ i18n (>= 0.7, < 2)
18
21
  minitest (~> 5.1)
19
- thread_safe (~> 0.3, >= 0.3.4)
20
22
  tzinfo (~> 1.1)
21
- addressable (2.5.1)
22
- public_suffix (~> 2.0, >= 2.0.2)
23
+ addressable (2.5.2)
24
+ public_suffix (>= 2.0.2, < 4.0)
25
+ aws-eventstream (1.0.1)
26
+ aws-partitions (1.97.0)
27
+ aws-sdk-core (3.24.0)
28
+ aws-eventstream (~> 1.0)
29
+ aws-partitions (~> 1.0)
30
+ aws-sigv4 (~> 1.0)
31
+ jmespath (~> 1.0)
32
+ aws-sdk-sqs (1.4.0)
33
+ aws-sdk-core (~> 3)
34
+ aws-sigv4 (~> 1.0)
35
+ aws-sigv4 (1.0.3)
23
36
  builder (3.2.3)
24
37
  codeclimate-test-reporter (1.0.8)
25
38
  simplecov (<= 0.13)
39
+ concurrent-ruby (1.0.5)
26
40
  crack (0.4.3)
27
41
  safe_yaml (~> 1.0.0)
28
42
  diff-lcs (1.3)
29
43
  docile (1.1.5)
30
- dotenv (2.2.1)
31
- excon (0.45.4)
32
- faraday (0.9.2)
44
+ dotenv (2.5.0)
45
+ excon (0.62.0)
46
+ factory_bot (4.10.0)
47
+ activesupport (>= 3.0.0)
48
+ faker (1.9.1)
49
+ i18n (>= 0.7)
50
+ faraday (0.15.2)
33
51
  multipart-post (>= 1.2, < 3)
34
52
  faraday-encoding (0.0.4)
35
53
  faraday
36
- faraday_middleware (0.10.1)
54
+ faraday_middleware (0.12.2)
37
55
  faraday (>= 0.7.4, < 1.0)
38
56
  gender_detector (1.0.0)
39
- hashdiff (0.3.4)
40
- i18n (0.8.4)
57
+ hashdiff (0.3.7)
58
+ i18n (1.1.0)
59
+ concurrent-ruby (~> 1.0)
60
+ jmespath (1.4.0)
41
61
  json (2.1.0)
42
- maremma (3.5.8)
43
- activesupport (>= 4.2.5)
62
+ maremma (4.1)
63
+ activesupport (>= 4.2.5, < 6)
44
64
  addressable (>= 2.3.6)
45
65
  builder (~> 3.2, >= 3.2.2)
46
- excon (~> 0.45.0)
47
- faraday (~> 0.9.2)
48
- faraday-encoding (~> 0.0.1)
49
- faraday_middleware (~> 0.10.0)
66
+ excon (~> 0.60)
67
+ faraday (~> 0.14)
68
+ faraday-encoding (~> 0.0.4)
69
+ faraday_middleware (~> 0.12.0)
50
70
  multi_json (~> 1.12)
51
- nokogiri (~> 1.6, >= 1.6.8)
52
- oj (~> 2.18, >= 2.18.1)
53
- mini_portile2 (2.2.0)
54
- minitest (5.10.2)
55
- multi_json (1.12.1)
71
+ nokogiri (~> 1.8.1)
72
+ oj (>= 2.8.3)
73
+ mini_portile2 (2.3.0)
74
+ minitest (5.11.3)
75
+ multi_json (1.13.1)
56
76
  multipart-post (2.0.0)
57
77
  namae (0.11.3)
58
- nokogiri (1.8.0)
59
- mini_portile2 (~> 2.2.0)
60
- oj (2.18.5)
61
- public_suffix (2.0.5)
62
- rack (2.0.3)
63
- rack-test (0.6.3)
64
- rack (>= 1.0)
65
- rake (12.0.0)
66
- rspec (3.6.0)
67
- rspec-core (~> 3.6.0)
68
- rspec-expectations (~> 3.6.0)
69
- rspec-mocks (~> 3.6.0)
70
- rspec-core (3.6.0)
71
- rspec-support (~> 3.6.0)
72
- rspec-expectations (3.6.0)
78
+ nokogiri (1.8.4)
79
+ mini_portile2 (~> 2.3.0)
80
+ oj (3.6.5)
81
+ public_suffix (3.0.2)
82
+ rack (2.0.5)
83
+ rack-test (0.8.3)
84
+ rack (>= 1.0, < 3)
85
+ rake (12.3.1)
86
+ rspec (3.8.0)
87
+ rspec-core (~> 3.8.0)
88
+ rspec-expectations (~> 3.8.0)
89
+ rspec-mocks (~> 3.8.0)
90
+ rspec-core (3.8.0)
91
+ rspec-support (~> 3.8.0)
92
+ rspec-expectations (3.8.1)
73
93
  diff-lcs (>= 1.2.0, < 2.0)
74
- rspec-support (~> 3.6.0)
75
- rspec-mocks (3.6.0)
94
+ rspec-support (~> 3.8.0)
95
+ rspec-mocks (3.8.0)
76
96
  diff-lcs (>= 1.2.0, < 2.0)
77
- rspec-support (~> 3.6.0)
78
- rspec-support (3.6.0)
97
+ rspec-support (~> 3.8.0)
98
+ rspec-support (3.8.0)
79
99
  safe_yaml (1.0.4)
80
- simplecov (0.12.0)
100
+ simplecov (0.13.0)
81
101
  docile (~> 1.1.0)
82
102
  json (>= 1.8, < 3)
83
103
  simplecov-html (~> 0.10.0)
84
- simplecov-html (0.10.1)
85
- slack-notifier (2.2.2)
86
- thor (0.19.4)
104
+ simplecov-html (0.10.2)
105
+ slack-notifier (2.3.2)
106
+ thor (0.20.0)
87
107
  thread_safe (0.3.6)
88
- tzinfo (1.2.3)
108
+ tzinfo (1.2.5)
89
109
  thread_safe (~> 0.1)
90
110
  vcr (3.0.3)
91
- webmock (1.24.6)
111
+ webmock (3.4.2)
92
112
  addressable (>= 2.3.6)
93
113
  crack (>= 0.3.2)
94
114
  hashdiff
@@ -98,14 +118,16 @@ PLATFORMS
98
118
 
99
119
  DEPENDENCIES
100
120
  bundler (~> 1.0)
101
- codeclimate-test-reporter (~> 1.0, >= 1.0.0)
121
+ codeclimate-test-reporter (~> 1.0)
122
+ factory_bot
123
+ faker
102
124
  rack-test (~> 0)
103
125
  rake (~> 12.0)
104
126
  rspec (~> 3.4)
105
- simplecov (~> 0.12.0)
127
+ simplecov
106
128
  toccatore!
107
129
  vcr (~> 3.0, >= 3.0.3)
108
- webmock (~> 1.22, >= 1.22.3)
130
+ webmock (~> 3.0, >= 3.0.1)
109
131
 
110
132
  BUNDLED WITH
111
- 1.12.5
133
+ 1.16.1
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![Code Climate](https://codeclimate.com/github/datacite/toccatore/badges/gpa.svg)](https://codeclimate.com/github/datacite/toccatore)
5
5
  [![Test Coverage](https://codeclimate.com/github/datacite/toccatore/badges/coverage.svg)](https://codeclimate.com/github/datacite/toccatore/coverage)
6
6
 
7
- Agent for Event Data service, providing links to ORCID IDs and DOIs not from DataCite as related identifiers in DataCite metadata.
7
+ Agent for Event Data service. Extracts links to ORCID IDs and DOIs not from DataCite from DataCite metadata, and pushes them to the other services.
8
8
 
9
9
  ## Installation and use
10
10
 
@@ -72,7 +72,12 @@ module Toccatore
72
72
  (0...total_pages).each do |page|
73
73
  options[:offset] = page * job_batch_size
74
74
  options[:total] = total
75
- error_total += process_data(options)
75
+ err = process_data(options)
76
+ if err.is_a?(Integer)
77
+ error_total += err
78
+ else
79
+ puts err.inspect
80
+ end
76
81
  end
77
82
  text = "#{total} works processed with #{error_total} errors for date range #{options[:from_date]} - #{options[:until_date]}."
78
83
  else
@@ -82,7 +87,13 @@ module Toccatore
82
87
  puts text
83
88
 
84
89
  # send slack notification
85
- options[:level] = total > 0 ? "good" : "warning"
90
+ if total == 0
91
+ options[:level] = "warning"
92
+ elsif error_total > 0
93
+ options[:level] = "danger"
94
+ else
95
+ options[:level] = "good"
96
+ end
86
97
  options[:title] = "Report for #{source_id}"
87
98
  send_notification_to_slack(text, options) if options[:slack_webhook_url].present?
88
99
 
@@ -145,8 +156,8 @@ module Toccatore
145
156
  notifier = Slack::Notifier.new options[:slack_webhook_url],
146
157
  username: "Event Data Agent",
147
158
  icon_url: ICON_URL
148
- response = notifier.ping attachments: [attachment]
149
- response.body
159
+ response = notifier.post attachments: [attachment]
160
+ response.first
150
161
  end
151
162
 
152
163
  def get_doi_ra(prefix)
data/lib/toccatore/cli.rb CHANGED
@@ -46,5 +46,17 @@ module Toccatore
46
46
  datacite_related = Toccatore::DataciteRelated.new
47
47
  datacite_related.queue_jobs(datacite_related.unfreeze(options))
48
48
  end
49
+
50
+ desc "usage_update", "push DataCite DOIs usage from DLM Hub to Event Data"
51
+ method_option :access_token, type: :string, required: true
52
+ method_option :source_token, type: :string, required: true
53
+ method_option :push_url, type: :string
54
+ method_option :slack_webhook_url, type: :string
55
+ method_option :doi, type: :string
56
+ method_option :jsonapi, :type => :boolean, default: true
57
+ def usage_update
58
+ usage_update = Toccatore::UsageUpdate.new
59
+ usage_update.queue_jobs(usage_update.unfreeze(options))
60
+ end
49
61
  end
50
62
  end
@@ -45,7 +45,7 @@ module Toccatore
45
45
  "relation_type_id" => raw_relation_type.underscore,
46
46
  "source_id" => "datacite",
47
47
  "source_token" => options[:source_token],
48
- "occurred_at" => item.fetch("minted"),
48
+ "occurred_at" => item.fetch("updated"),
49
49
  "license" => LICENSE }
50
50
  else
51
51
  ssum
@@ -58,7 +58,10 @@ module Toccatore
58
58
  end
59
59
 
60
60
  def push_item(item, options={})
61
- return OpenStruct.new(body: { "errors" => [{ "title" => "Access token missing." }] }) if options[:access_token].blank?
61
+ if options[:access_token].blank?
62
+ puts "Access token missing."
63
+ return 1
64
+ end
62
65
 
63
66
  host = options[:push_url].presence || "https://bus.eventdata.crossref.org"
64
67
  push_url = host + "/events"
@@ -67,7 +70,16 @@ module Toccatore
67
70
  data = { "data" => {
68
71
  "id" => item["id"],
69
72
  "type" => "events",
70
- "attributes" => item.except("id") }}
73
+ "attributes" => {
74
+ "message-action" => item["message_action"],
75
+ "subj-id" => item["subj_id"],
76
+ "obj-id" => item["obj_id"],
77
+ "relation-type-id" => item["relation_type_id"],
78
+ "source-id" => "datacite-crossref",
79
+ "source-token" => item["source_token"],
80
+ "occurred-at" => item["occurred_at"],
81
+ "license" => item["license"] } }}
82
+
71
83
  response = Maremma.post(push_url, data: data.to_json,
72
84
  bearer: options[:access_token],
73
85
  content_type: 'json',
@@ -83,6 +95,9 @@ module Toccatore
83
95
  if response.status == 201
84
96
  puts "#{item['subj_id']} #{item['relation_type_id']} #{item['obj_id']} pushed to Event Data service."
85
97
  0
98
+ elsif response.status == 409
99
+ puts "#{item['subj_id']} #{item['relation_type_id']} #{item['obj_id']} already pushed to Event Data service."
100
+ 0
86
101
  elsif response.body["errors"].present?
87
102
  puts "#{item['subj_id']} #{item['relation_type_id']} #{item['obj_id']} had an error:"
88
103
  puts "#{response.body['errors'].first['title']}"
@@ -44,9 +44,13 @@ module Toccatore
44
44
  end
45
45
 
46
46
  def push_item(item, options={})
47
- return OpenStruct.new(body: { "errors" => [{ "title" => "Access token missing." }] }) if options[:access_token].blank?
47
+ if options[:access_token].blank?
48
+ puts "Access token missing."
49
+ return 1
50
+ end
48
51
 
49
- push_url = (options[:push_url].presence || "https://profiles.datacite.org/api") + "/claims"
52
+ host = options[:push_url].presence || "https://profiles.datacite.org/api"
53
+ push_url = host + "/claims"
50
54
 
51
55
  response = Maremma.post(push_url, data: { "claim" => item }.to_json,
52
56
  bearer: options[:access_token],
@@ -0,0 +1,56 @@
1
+ require 'aws-sdk-sqs'
2
+
3
+ module Toccatore
4
+ module Queue
5
+
6
+ def queue options={}
7
+ puts "Queue name has not been specified" unless ENV['ENVIRONMENT'].present?
8
+ puts "AWS_REGION has not been specified" unless ENV['AWS_REGION'].present?
9
+ region = ENV['AWS_REGION'] ||= 'eu-west-1'
10
+ Aws::SQS::Client.new(region: region.to_s, stub_responses: false)
11
+ end
12
+
13
+ def get_total options={}
14
+ req = @sqs.get_queue_attributes(
15
+ {
16
+ queue_url: queue_url, attribute_names:
17
+ [
18
+ 'ApproximateNumberOfMessages',
19
+ 'ApproximateNumberOfMessagesNotVisible'
20
+ ]
21
+ }
22
+ )
23
+
24
+ msgs_available = req.attributes['ApproximateNumberOfMessages']
25
+ msgs_in_flight = req.attributes['ApproximateNumberOfMessagesNotVisible']
26
+ msgs_available.to_i
27
+ end
28
+
29
+ def get_message options={}
30
+ @sqs.receive_message(queue_url: queue_url, max_number_of_messages: 1, wait_time_seconds: 1)
31
+ end
32
+
33
+ def delete_message options={}
34
+ return 1 if options.messages.size < 1
35
+ reponse = @sqs.delete_message({
36
+ queue_url: queue_url,
37
+ receipt_handle: options.messages[0][:receipt_handle]
38
+ })
39
+ if reponse.successful?
40
+ puts "Message #{options.messages[0][:receipt_handle]} deleted"
41
+ 0
42
+ else
43
+ puts "Could NOT delete Message #{options.messages[0][:receipt_handle]}"
44
+ 1
45
+ end
46
+
47
+ end
48
+
49
+ def queue_url options={}
50
+ options[:queue_name] ||= "#{ENV['ENVIRONMENT']}_usage"
51
+ queue_name = options[:queue_name]
52
+ # puts "Using #{@sqs.get_queue_url(queue_name: queue_name).queue_url} queue"
53
+ @sqs.get_queue_url(queue_name: queue_name).queue_url
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,183 @@
1
+ require_relative 'base'
2
+
3
+
4
+ module Toccatore
5
+ class UsageUpdate < Base
6
+ include Toccatore::Queue
7
+ LICENSE = "https://creativecommons.org/publicdomain/zero/1.0/"
8
+
9
+
10
+ def initialize options={}
11
+ @sqs = queue options
12
+ end
13
+
14
+ def queue_jobs(options={})
15
+
16
+ total = get_total(options)
17
+
18
+ if total < 1
19
+ text = "No works found for in the Usage Reports Queue."
20
+ end
21
+
22
+ error_total = 0
23
+ proccessed_messages = 0
24
+ num_messages = total
25
+ while num_messages != 0
26
+ processed = process_data(options)
27
+ error_total += processed
28
+ proccessed_messages += 1 if processed == 0
29
+ num_messages -= proccessed_messages
30
+ end
31
+ text = "#{proccessed_messages} works processed with #{error_total} errors for Usage Reports Queue #{queue_url}"
32
+
33
+ puts text
34
+ # send slack notification
35
+ options[:level] = total > 0 ? "good" : "warning"
36
+ options[:title] = "Report for #{source_id}"
37
+ send_notification_to_slack(text, options) if options[:slack_webhook_url].present?
38
+
39
+ # return number of works queued
40
+ proccessed_messages
41
+ end
42
+
43
+ def process_data(options = {})
44
+ errors = 0
45
+ message = get_message
46
+ unless message.messages.empty?
47
+ data = get_data(message)
48
+ events = parse_data(data, options)
49
+ errors = push_data(events, options)
50
+ if errors < 1
51
+ delete_message message
52
+ end
53
+ end
54
+ errors
55
+ end
56
+
57
+ def get_data reponse
58
+ body = JSON.parse(reponse.messages[0].body)
59
+ url = body["report_id"]
60
+ host = URI.parse(body["report_id"]).host.downcase
61
+ puts url
62
+ puts host
63
+ puts body
64
+ puts "%%%%%%%%%%"
65
+ Maremma.get(url, timeout: 120, host: host)
66
+ end
67
+
68
+
69
+ # method returns number of errors
70
+ def push_data(items, options={})
71
+ if items.empty?
72
+ puts "No works found in the Queue."
73
+ 0
74
+ elsif options[:access_token].blank?
75
+ puts "An error occured: Access token missing."
76
+ options[:total]
77
+ else
78
+ error_total = 0
79
+ Array(items).each do |item|
80
+ puts item
81
+ puts "*************"
82
+ error_total += push_item(item, options)
83
+ end
84
+ error_total
85
+ end
86
+ end
87
+
88
+ def source_id
89
+ "usage_update"
90
+ end
91
+
92
+ def format_event type, data, options
93
+ fail "Not type given. Report #{data[:report_id]} not proccessed" if type.blank?
94
+ fail "Access token missing." if options[:source_token].blank?
95
+ fail "Report_id is missing" if data[:report_id].blank?
96
+
97
+ { "uuid" => SecureRandom.uuid,
98
+ "message-action" => "create",
99
+ "subj-id" => data[:report_id],
100
+ "subj"=> {
101
+ "pid"=> data[:report_id],
102
+ "issued"=> data[:created]
103
+ },
104
+ "total"=> data[:count],
105
+ "obj-id" => data[:pid],
106
+ "relation-type-id" => type,
107
+ "source-id" => "datacite-usage",
108
+ "source-token" => options[:source_token],
109
+ "occurred-at" => data[:created_at],
110
+ "license" => LICENSE
111
+ }
112
+ end
113
+
114
+ def parse_data(result, options={})
115
+ puts result.status
116
+ puts "*************"
117
+ return result.body.fetch("errors") if result.body.fetch("errors", nil).present?
118
+ return [{ "errors" => { "title" => "The report is blank" }}] if result.body.blank?
119
+
120
+ items = result.body.dig("data","report","report-datasets")
121
+ header = result.body.dig("data","report","report-header")
122
+ report_id = result.url
123
+
124
+ created = header.fetch("created")
125
+ Array.wrap(items).reduce([]) do |x, item|
126
+ data = {}
127
+ data[:doi] = item.dig("dataset-id").first.dig("value")
128
+ data[:pid] = normalize_doi(data[:doi])
129
+ data[:created] = created
130
+ data[:report_id] = report_id
131
+ data[:created_at] = created
132
+
133
+ instances = item.dig("performance", 0, "instance")
134
+
135
+ return x += [OpenStruct.new(body: { "errors" => "There are too many instances in #{data[:doi]} for report #{report_id}. There can only be 4" })] if instances.size > 8
136
+
137
+ x += Array.wrap(instances).reduce([]) do |ssum, instance|
138
+ data[:count] = instance.dig("count")
139
+ event_type = "#{instance.dig("metric-type")}-#{instance.dig("access-method")}"
140
+ ssum << format_event(event_type, data, options)
141
+ ssum
142
+ end
143
+ end
144
+ end
145
+
146
+ def push_item(item, options={})
147
+ if item["subj-id"].blank?
148
+ puts OpenStruct.new(body: { "errors" => [{ "title" => "There is no Subject" }] })
149
+ return 1
150
+ elsif options[:access_token].blank?
151
+ puts OpenStruct.new(body: { "errors" => [{ "title" => "Access token missing." }] })
152
+ return 1
153
+ elsif item["errors"].present?
154
+ puts OpenStruct.new(body: { "errors" => [{ "title" => "#{item["errors"]["title"]}" }] })
155
+ return 1
156
+ end
157
+
158
+ host = options[:push_url].presence || "https://api.test.datacite.org"
159
+ push_url = host + "/events/" + item["uuid"].to_s
160
+ data = { "data" => {
161
+ "id" => item["uuid"],
162
+ "type" => "events",
163
+ "attributes" => item.except("id") }}
164
+
165
+ response = Maremma.put(push_url, data: data.to_json,
166
+ bearer: options[:access_token],
167
+ content_type: 'json',
168
+ host: host)
169
+
170
+ if response.status == 201
171
+ puts "#{item['subj-id']} #{item['relation-type-id']} #{item['obj-id']} pushed to Event Data service."
172
+ 0
173
+ elsif response.status == 200
174
+ puts "#{item['subj-id']} #{item['relation-type-id']} #{item['obj-id']} pushed to Event Data service for update."
175
+ 0
176
+ elsif response.body["errors"].present?
177
+ puts "#{item['subj-id']} #{item['relation-type-id']} #{item['obj-id']} had an error:"
178
+ puts "#{response.body['errors'].first['title']}"
179
+ 1
180
+ end
181
+ end
182
+ end
183
+ end
@@ -1,3 +1,3 @@
1
1
  module Toccatore
2
- VERSION = "0.3.9"
2
+ VERSION = "0.4.15"
3
3
  end
data/lib/toccatore.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require "toccatore/orcid_update"
2
2
  require "toccatore/datacite_related"
3
+ require "toccatore/queue"
4
+ require "toccatore/usage_update"
3
5
  require "toccatore/cli"
4
6
  require "toccatore/version"
data/spec/base_spec.rb CHANGED
@@ -35,7 +35,7 @@ describe Toccatore::Base, vcr: true do
35
35
  it "datacite_related" do
36
36
  text = "12 works processed for date range 2015-04-07 - 2015-04-08."
37
37
  options = { title: "Report for datacite_related", slack_webhook_url: slack_webhook_url }
38
- expect(subject.send_notification_to_slack(text, options)).to eq("ok")
38
+ expect(subject.send_notification_to_slack(text, options)).to be_kind_of(Net::HTTPOK)
39
39
  end
40
40
 
41
41
  it "datacite_related no works" do
@@ -43,13 +43,13 @@ describe Toccatore::Base, vcr: true do
43
43
  options = { title: "Report for datacite_related",
44
44
  slack_webhook_url: slack_webhook_url,
45
45
  level: "warning" }
46
- expect(subject.send_notification_to_slack(text, options)).to eq("ok")
46
+ expect(subject.send_notification_to_slack(text, options)).to be_kind_of(Net::HTTPOK)
47
47
  end
48
48
 
49
49
  it "orcid_update" do
50
50
  text = "12 works processed for date range 2015-04-07 - 2015-04-08."
51
51
  options = { title: "Report for orcid_update", slack_webhook_url: slack_webhook_url }
52
- expect(subject.send_notification_to_slack(text, options)).to eq("ok")
52
+ expect(subject.send_notification_to_slack(text, options)).to be_kind_of(Net::HTTPOK)
53
53
  end
54
54
 
55
55
  it "orcid_update no works" do
@@ -57,7 +57,7 @@ describe Toccatore::Base, vcr: true do
57
57
  options = { title: "Report for orcid_update",
58
58
  slack_webhook_url: slack_webhook_url,
59
59
  level: "warning" }
60
- expect(subject.send_notification_to_slack(text, options)).to eq("ok")
60
+ expect(subject.send_notification_to_slack(text, options)).to be_kind_of(Net::HTTPOK)
61
61
  end
62
62
  end
63
63