globus_client 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b27d41e017d13090e7a92e046534b7f0cee1fa368fb56599cdbafdcd8e10e5b6
4
- data.tar.gz: a265b2f06f90e90ada9bb8c89f5ded515ace614dbf107aabff94ad0c8ec810d3
3
+ metadata.gz: 77e44f70f4c6ee02299ac4718e8ed5d1c2c88d58c71a4ba2c3bfbe970e2bb5df
4
+ data.tar.gz: b74fbc9c11f7b9c9fdadac074fe8709711f0065d03ab01fcecb159374446bb9b
5
5
  SHA512:
6
- metadata.gz: 3415d9b36af6b543b62b1c723ef7fd4caa601cff3f727e5657b052eb341c28efe208188d36a2c39181f56f1a88016b5f79a3f3a7f932ba979765b94dc18d7931
7
- data.tar.gz: a8a480efefdeccc418ce7a2e0cd3b25905f4ea426cfd40dd4c886e7f39e4ea7457a474297d83b6d98d162153bf2fd980f83b83b908d83bd6109d3498195aff80
6
+ metadata.gz: 26d0923724fc1301b344b190d347abd25a1c6e17c57214f424df46d3739fc64ead270e9ae8eb3eddecdfc6700d6c52bc935cda654aef8109a01b45a5d187ca39
7
+ data.tar.gz: a5c9e21ec3917f8c560ed34eaefb38af1253cddd582223e1986a78d165301443b689875a20a96f24ef1eb514aca19fbc7994af52c1f441b5db60d9428592cd0b
@@ -0,0 +1,19 @@
1
+ #!/bin/bash --login
2
+
3
+ # This script is called by our weekly dependency update job in Jenkins after updating Ruby and other deps
4
+
5
+ # Switch to Ruby 3.1 for Globus::Client (3.0 is default in Jenkinsfile)
6
+ rvm use 3.1.2@globus_client --create &&
7
+ gem install bundler &&
8
+ bundle install --gemfile Gemfile
9
+
10
+ standardrb --fix > globus_client_standard.txt
11
+
12
+ retVal=$?
13
+
14
+ git commit -am "Update to latest standard style guide"
15
+
16
+ if [ $retVal -ne 0 ]; then
17
+ echo "ERROR UPDATING RUBY TO STANDARD STYLE (globus_client)"
18
+ cat globus_client_standard.txt
19
+ fi
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,50 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.1
3
+ DisplayCopNames: true
4
+ SuggestExtensions: false
5
+ Exclude:
6
+ - bin/**
7
+ - vendor/bundle/**/*
8
+
9
+ # Per team developer playbook
10
+ RSpec/MultipleMemoizedHelpers:
11
+ Enabled: false
12
+
13
+ RSpec/BeEq: # new in 2.9.0
14
+ Enabled: true
15
+ RSpec/BeNil: # new in 2.9.0
16
+ Enabled: true
17
+ RSpec/ChangeByZero: # new in 2.11
18
+ Enabled: true
19
+ RSpec/ClassCheck: # new in 2.13
20
+ Enabled: true
21
+ RSpec/ExcessiveDocstringSpacing: # new in 2.5
22
+ Enabled: true
23
+ RSpec/IdenticalEqualityAssertion: # new in 2.4
24
+ Enabled: true
25
+ RSpec/NoExpectationExample: # new in 2.13
26
+ Enabled: true
27
+ RSpec/SortMetadata: # new in 2.14
28
+ Enabled: true
29
+ RSpec/SubjectDeclaration: # new in 2.5
30
+ Enabled: true
31
+ RSpec/VerifiedDoubleReference: # new in 2.10.0
32
+ Enabled: true
33
+ RSpec/Capybara/NegationMatcher: # new in 2.14
34
+ Enabled: true
35
+ RSpec/Capybara/SpecificActions: # new in 2.14
36
+ Enabled: true
37
+ RSpec/Capybara/SpecificFinders: # new in 2.13
38
+ Enabled: true
39
+ RSpec/Capybara/SpecificMatcher: # new in 2.12
40
+ Enabled: true
41
+ RSpec/FactoryBot/ConsistentParenthesesStyle: # new in 2.14
42
+ Enabled: true
43
+ RSpec/FactoryBot/SyntaxMethods: # new in 2.7
44
+ Enabled: true
45
+ RSpec/Rails/AvoidSetupHook: # new in 2.4
46
+ Enabled: true
47
+ RSpec/Rails/HaveHttpStatus: # new in 2.12
48
+ Enabled: true
49
+ RSpec/Rails/InferredSpecType: # new in 2.14
50
+ Enabled: true
data/.rubocop.yml ADDED
@@ -0,0 +1,15 @@
1
+ inherit_mode:
2
+ merge:
3
+ - Exclude
4
+
5
+ require:
6
+ - rubocop-performance
7
+ - rubocop-rspec
8
+ - standard
9
+
10
+ inherit_gem:
11
+ standard: config/base.yml
12
+
13
+ inherit_from:
14
+ - .rubocop/custom.yml
15
+ - .rubocop_todo.yml
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,7 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2022-10-27 22:53:23 UTC using RuboCop version 1.37.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
data/.standard.yml ADDED
@@ -0,0 +1 @@
1
+ parallel: true
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in globus_client.gemspec
6
+ gemspec
7
+
8
+ gem "byebug"
data/Gemfile.lock ADDED
@@ -0,0 +1,109 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ globus_client (0.1.0)
5
+ activesupport (>= 4.2, < 8)
6
+ faraday
7
+ zeitwerk
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activesupport (7.0.4)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 1.6, < 2)
15
+ minitest (>= 5.1)
16
+ tzinfo (~> 2.0)
17
+ addressable (2.8.1)
18
+ public_suffix (>= 2.0.2, < 6.0)
19
+ ast (2.4.2)
20
+ byebug (11.1.3)
21
+ concurrent-ruby (1.1.10)
22
+ crack (0.4.5)
23
+ rexml
24
+ diff-lcs (1.5.0)
25
+ docile (1.4.0)
26
+ faraday (2.7.1)
27
+ faraday-net_http (>= 2.0, < 3.1)
28
+ ruby2_keywords (>= 0.0.4)
29
+ faraday-net_http (3.0.2)
30
+ hashdiff (1.0.1)
31
+ i18n (1.12.0)
32
+ concurrent-ruby (~> 1.0)
33
+ json (2.6.2)
34
+ minitest (5.16.3)
35
+ parallel (1.22.1)
36
+ parser (3.1.2.1)
37
+ ast (~> 2.4.1)
38
+ public_suffix (5.0.0)
39
+ rainbow (3.1.1)
40
+ rake (13.0.6)
41
+ regexp_parser (2.6.1)
42
+ rexml (3.2.5)
43
+ rspec (3.12.0)
44
+ rspec-core (~> 3.12.0)
45
+ rspec-expectations (~> 3.12.0)
46
+ rspec-mocks (~> 3.12.0)
47
+ rspec-core (3.12.0)
48
+ rspec-support (~> 3.12.0)
49
+ rspec-expectations (3.12.0)
50
+ diff-lcs (>= 1.2.0, < 2.0)
51
+ rspec-support (~> 3.12.0)
52
+ rspec-mocks (3.12.0)
53
+ diff-lcs (>= 1.2.0, < 2.0)
54
+ rspec-support (~> 3.12.0)
55
+ rspec-support (3.12.0)
56
+ rubocop (1.39.0)
57
+ json (~> 2.3)
58
+ parallel (~> 1.10)
59
+ parser (>= 3.1.2.1)
60
+ rainbow (>= 2.2.2, < 4.0)
61
+ regexp_parser (>= 1.8, < 3.0)
62
+ rexml (>= 3.2.5, < 4.0)
63
+ rubocop-ast (>= 1.23.0, < 2.0)
64
+ ruby-progressbar (~> 1.7)
65
+ unicode-display_width (>= 1.4.0, < 3.0)
66
+ rubocop-ast (1.23.0)
67
+ parser (>= 3.1.1.0)
68
+ rubocop-performance (1.15.0)
69
+ rubocop (>= 1.7.0, < 2.0)
70
+ rubocop-ast (>= 0.4.0)
71
+ rubocop-rspec (2.15.0)
72
+ rubocop (~> 1.33)
73
+ ruby-progressbar (1.11.0)
74
+ ruby2_keywords (0.0.5)
75
+ simplecov (0.21.2)
76
+ docile (~> 1.1)
77
+ simplecov-html (~> 0.11)
78
+ simplecov_json_formatter (~> 0.1)
79
+ simplecov-html (0.12.3)
80
+ simplecov_json_formatter (0.1.4)
81
+ standard (1.18.0)
82
+ rubocop (= 1.39.0)
83
+ rubocop-performance (= 1.15.0)
84
+ tzinfo (2.0.5)
85
+ concurrent-ruby (~> 1.0)
86
+ unicode-display_width (2.3.0)
87
+ webmock (3.18.1)
88
+ addressable (>= 2.8.0)
89
+ crack (>= 0.3.2)
90
+ hashdiff (>= 0.4.0, < 2.0.0)
91
+ zeitwerk (2.6.6)
92
+
93
+ PLATFORMS
94
+ x86_64-darwin-20
95
+ x86_64-darwin-21
96
+ x86_64-linux
97
+
98
+ DEPENDENCIES
99
+ byebug
100
+ globus_client!
101
+ rake (~> 13.0)
102
+ rspec (~> 3.0)
103
+ rubocop-rspec
104
+ simplecov
105
+ standard
106
+ webmock
107
+
108
+ BUNDLED WITH
109
+ 2.3.19
data/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+
2
+ Copyright (c) 2022 by The Board of Trustees of the Leland Stanford
3
+ Junior University. All rights reserved.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License"); you
6
+ may not use this file except in compliance with the License. You
7
+ may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14
+ implied. See the License for the specific language governing
15
+ permissions and limitations under the License.
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ [![Gem Version](https://badge.fury.io/rb/globus_client.svg)](https://badge.fury.io/rb/globus_client)
2
+ [![CircleCI](https://circleci.com/gh/sul-dlss/globus_client.svg?style=svg)](https://circleci.com/gh/sul-dlss/globus_client)
3
+ [![Code Climate](https://codeclimate.com/github/sul-dlss/globus_client/badges/gpa.svg)](https://codeclimate.com/github/sul-dlss/globus_client)
4
+ [![Code Climate Test Coverage](https://api.codeclimate.com/v1/badges/8e6bf1a5d3fc86a6fbd0/test_coverage)](https://codeclimate.com/github/sul-dlss/globus_client/test_coverage)
5
+
6
+ # Globus::Client
7
+
8
+ Globus::Client is a Ruby gem that acts as a client to the RESTful HTTP APIs provided by the [Globus service](https://docs.globus.org/api/).
9
+
10
+ ## Installation
11
+
12
+ Install the gem and add to the application's Gemfile by executing:
13
+
14
+ $ bundle add globus_client
15
+
16
+ If bundler is not being used to manage dependencies, install the gem by executing:
17
+
18
+ $ gem install globus_client
19
+
20
+ ## Usage
21
+
22
+ For one-off requests:
23
+
24
+ ```ruby
25
+ require 'globus/client'
26
+
27
+ # NOTE: The settings below live in the consumer, not in the gem.
28
+ client = Globus::Client.configure(
29
+ client_id: Settings.globus.client_id,
30
+ client_secret: Settings.globus.client_secret,
31
+ uploads_directory: Settings.globus.uploads_directory,
32
+ transfer_endpoint_id: Settings.globus.transfer_endpoint_id
33
+ )
34
+ client.mkdir(user_id: 'mjgiarlo', work_id: 1234, work_version: 1)
35
+ ```
36
+
37
+ You can also invoke methods directly on the client class, which is useful in a
38
+ Rails application environment where you might initialize the client in an
39
+ initializer and then invoke client methods in many other contexts where you want
40
+ to be sure configuration has already occurred, e.g.:
41
+
42
+ ```ruby
43
+ # config/initializers/globus_client.rb
44
+ Globus::Client.configure(
45
+ client_id: Settings.globus.client_id,
46
+ client_secret: Settings.globus.client_secret,
47
+ uploads_directory: Settings.globus.uploads_directory,
48
+ transfer_endpoint_id: Settings.globus.transfer_endpoint_id
49
+ )
50
+
51
+ # app/services/my_globus_service.rb
52
+ # ...
53
+ def create_user_directory
54
+ Globus::Client.mkdir(user_id: 'mjgiarlo', work_id: 1234, work_version: 1)
55
+ end
56
+ # ...
57
+ ```
58
+
59
+ ## Development
60
+
61
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
62
+ `rake spec` to run the tests. You can also run `bin/console` for an interactive
63
+ prompt that will allow you to experiment.
64
+
65
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
66
+
67
+ ## Contributing
68
+
69
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sul-dlss/globus_client.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+ require "rubocop/rake_task"
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new
9
+
10
+ task default: %i[rubocop spec]
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require "globus/client/version"
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "globus_client"
9
+ spec.version = Globus::Client::VERSION
10
+ spec.authors = ["Aaron Collier", "Laura Wrubel", "Mike Giarlo"]
11
+ spec.email = ["aaron.collier@stanford.edu", "lwrubel@stanford.edu", "mjgiarlo@stanford.edu"]
12
+
13
+ spec.summary = "Interface for interacting with the Globus API."
14
+ spec.description = "This provides API interaction with the Globus API"
15
+ spec.homepage = "https://github.com/sul-dlss/globus_client"
16
+ spec.required_ruby_version = ">= 2.6.0"
17
+
18
+ spec.metadata["homepage_uri"] = spec.homepage
19
+ spec.metadata["source_code_uri"] = "https://github.com/sul-dlss/globus_client"
20
+ spec.metadata["changelog_uri"] = "https://github.com/sul-dlss/globus_client/releases"
21
+ spec.metadata["rubygems_mfa_required"] = "true"
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(__dir__) do
26
+ `git ls-files -z`.split("\x0").reject do |f|
27
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
28
+ end
29
+ end
30
+ spec.bindir = "exe"
31
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ spec.add_dependency "activesupport", ">= 4.2", "< 8"
35
+ spec.add_dependency "faraday"
36
+ spec.add_dependency "zeitwerk"
37
+
38
+ spec.add_development_dependency "rake", "~> 13.0"
39
+ spec.add_development_dependency "rspec", "~> 3.0"
40
+ spec.add_development_dependency "standard"
41
+ spec.add_development_dependency "rubocop-rspec"
42
+ spec.add_development_dependency "simplecov"
43
+ spec.add_development_dependency "webmock"
44
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Globus
4
+ class Client
5
+ # The namespace for the "login" command
6
+ class Authenticator
7
+ def self.token(client_id, client_secret, auth_url)
8
+ new(client_id, client_secret, auth_url).token
9
+ end
10
+
11
+ def initialize(client_id, client_secret, auth_url)
12
+ @client_id = client_id
13
+ @client_secret = client_secret
14
+ @auth_url = auth_url
15
+ end
16
+
17
+ # Request an access_token
18
+ def token
19
+ response = connection.post("/v2/oauth2/token", form_data)
20
+
21
+ JSON.parse(response.body)["access_token"]
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :client_id, :client_secret, :auth_url
27
+
28
+ def connection
29
+ Faraday.new(url: auth_url)
30
+ end
31
+
32
+ def form_data
33
+ {
34
+ client_id:,
35
+ client_secret:,
36
+ encoding: "form",
37
+ grant_type: "client_credentials",
38
+ scope: "urn:globus:auth:scope:transfer.api.globus.org:all"
39
+ }
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Globus
4
+ class Client
5
+ # The namespace for endpoint API operations
6
+ class Endpoint
7
+ # @param config [#token, #uploads_directory, #transfer_endpoint_id, #transfer_url, #auth_url] configuration for the gem
8
+ # @param user_id [String] conventionally, we use the SUNet ID, not an email address
9
+ # @param work_id [#to_s] the identifier of the work (e.g., an H2 work)
10
+ # @param work_version [#to_s] the version of the work (e.g., an H2 version)
11
+ def initialize(config, user_id:, work_id:, work_version:)
12
+ @config = config
13
+ @user_id = user_id
14
+ @work_id = work_id
15
+ @work_version = work_version
16
+ end
17
+
18
+ # This is a temporary method to show parsing of data returned.
19
+ def length
20
+ objects["total"]
21
+ end
22
+
23
+ # Create a directory https://docs.globus.org/api/transfer/file_operations/#make_directory
24
+ def mkdir
25
+ # transfer API does not support recursive directory creation
26
+ paths.each do |path|
27
+ response = call_mkdir(path)
28
+ next if response.success?
29
+
30
+ # if directory already exists
31
+ if response.status == 502
32
+ error = JSON.parse(response.body)
33
+ next if error["code"] == "ExternalError.MkdirFailedExists"
34
+ end
35
+
36
+ UnexpectedResponse.call(response)
37
+ end
38
+ end
39
+
40
+ # Assign a user read/write permissions for a directory https://docs.globus.org/api/transfer/acl/#rest_access_create
41
+ def set_permissions
42
+ path = "#{config.uploads_directory}/#{user_id}/work#{work_id}/version#{work_version}/"
43
+ identity = Globus::Client::Identity.new(config)
44
+ id = identity.get_identity_id(user_id)
45
+ call_access(path:, id:, user_id:)
46
+ end
47
+
48
+ private
49
+
50
+ attr_reader :config, :user_id, :work_id, :work_version
51
+
52
+ def connection
53
+ # Transfer API connection
54
+ Faraday.new(
55
+ url: config.transfer_url,
56
+ headers: {Authorization: "Bearer #{config.token}"}
57
+ )
58
+ end
59
+
60
+ # Builds up a path from a list of path elements. E.g., input would look like:
61
+ # ["mjgiarlo", "work123", "version1"]
62
+ # And this method returns:
63
+ # ["/uploads/mjgiarlo/", "/uploads/mjgiarlo/work123/", "/uploads/mjgiarlo/work123/version1/"]
64
+ def paths
65
+ path_segments.map.with_index do |_segment, index|
66
+ File.join(config.uploads_directory, path_segments.slice(..index)).concat("/")
67
+ end
68
+ end
69
+
70
+ def path_segments
71
+ [user_id, "work#{work_id}", "version#{work_version}"]
72
+ end
73
+
74
+ def endpoint
75
+ "/v0.10/operation/endpoint/#{config.transfer_endpoint_id}"
76
+ end
77
+
78
+ # @return [Faraday::Response]
79
+ def call_mkdir(path)
80
+ connection.post("#{endpoint}/mkdir") do |req|
81
+ req.headers["Content-Type"] = "application/json"
82
+ req.body = {
83
+ DATA_TYPE: "mkdir",
84
+ path:
85
+ }.to_json
86
+ end
87
+ end
88
+
89
+ # Makes the API call to Globus to set permissions
90
+ # @param path [String] the directory on the globus endpoint
91
+ # @param id [String] globus identifier associated with the user_id email
92
+ # @param user_id [String] user_id, not email address
93
+ # @return [Faraday::Response]
94
+ def call_access(path:, id:, user_id:)
95
+ response = connection.post("#{endpoint}/access") do |req|
96
+ req.body = {
97
+ DATA_TYPE: "access",
98
+ principal_type: "identity",
99
+ principal: id,
100
+ path:,
101
+ permissions: "rw",
102
+ notify_email: "#{user_id}@stanford.edu"
103
+ }.to_json
104
+ req.headers["Content-Type"] = "application/json"
105
+ end
106
+ UnexpectedResponse.call(response) unless response.success?
107
+
108
+ response
109
+ end
110
+
111
+ def objects
112
+ # List files at an endpoint https://docs.globus.org/api/transfer/file_operations/#list_directory_contents
113
+ response = connection.get("#{endpoint}/ls")
114
+ UnexpectedResponse.call(response) unless response.success?
115
+ JSON.parse(response.body)
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Globus
4
+ class Client
5
+ # Lookup of a Globus identity ID
6
+ class Identity
7
+ def initialize(config)
8
+ @config = config
9
+ end
10
+
11
+ def get_identity_id(sunetid)
12
+ @email = "#{sunetid}@stanford.edu"
13
+
14
+ response = lookup_identity
15
+ UnexpectedResponse.call(response) unless response.success?
16
+
17
+ data = JSON.parse(response.body)
18
+ extract_id(data)
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :config
24
+
25
+ def connection
26
+ Faraday.new(url: config.auth_url)
27
+ end
28
+
29
+ def lookup_identity
30
+ id_endpoint = "/v2/api/identities"
31
+ connection.get(id_endpoint) do |req|
32
+ req.params["usernames"] = @email
33
+ req.headers["Authorization"] = "Bearer #{config.token}"
34
+ end
35
+ end
36
+
37
+ def extract_id(data)
38
+ identities = data["identities"]
39
+ # Select identity with "used" or "private" status
40
+ matching_users = identities.select { |id| id["username"] == @email }
41
+ active_users = matching_users.select { |user| (user["status"] == "used" || user["status"] == "private") }
42
+ raise "No matching active Globus user found for #{@email}." if active_users.empty?
43
+
44
+ active_users.first["id"]
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Globus
4
+ class Client
5
+ # Handles unexpected responses when communicating with Globus
6
+ class UnexpectedResponse
7
+ # Error raised when the Globus Auth or Transfer API returns a 400 error
8
+ class BadRequestError < StandardError; end
9
+
10
+ # Error raised by the Globus Auth API returns a 401 Unauthorized
11
+ class UnauthorizedError < StandardError; end
12
+
13
+ # Error raised when the Globus Auth or Transfer API returns a 403 Forbidden
14
+ class ForbiddenError < StandardError; end
15
+
16
+ # Error raised when the Globus Auth or Transfer API returns a 404 NotFound
17
+ class ResourceNotFound < StandardError; end
18
+
19
+ # Error raised when the Globus Transfer API returns a 502 Bad Gateway
20
+ class EndpointError < StandardError; end
21
+
22
+ # Error raised when the remote server returns a 503 Bad Gateway
23
+ class ServiceUnavailable < StandardError; end
24
+
25
+ # @param [Faraday::Response] response
26
+ # https://docs.globus.org/api/transfer/file_operations/#common_errors
27
+ # https://docs.globus.org/api/transfer/file_operations/#errors
28
+ # https://docs.globus.org/api/transfer/acl/#common_errors
29
+ # https://docs.globus.org/api/auth/reference/
30
+ def self.call(response)
31
+ case response.status
32
+ when 400
33
+ raise BadRequestError, "Invalid path or another error with the request: #{response.body}"
34
+ when 401
35
+ raise UnauthorizedError, "There was a problem with the access token: #{response.body} "
36
+ when 403
37
+ raise ForbiddenError, "The operation requires privileges which the client does not have: #{response.body}"
38
+ when 404
39
+ raise ResourceNotFound, "Endpoint ID not found or resource does not exist: #{response.body}"
40
+ when 502
41
+ raise EndpointError, "Other error with endpoint: #{response.body}"
42
+ when 503
43
+ raise ServiceUnavailable, "The service is down for maintenance."
44
+ else
45
+ raise StandardError, "Unexpected response: #{response.status} #{response.body}"
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Globus
4
+ class Client
5
+ VERSION = "0.2.0"
6
+ end
7
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/delegation"
4
+ require "faraday"
5
+ require "ostruct"
6
+ require "singleton"
7
+ require "zeitwerk"
8
+
9
+ # Load the gem's internal dependencies
10
+ loader = Zeitwerk::Loader.new
11
+ loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
12
+ loader.push_dir(File.absolute_path("#{__FILE__}/../.."))
13
+ loader.setup
14
+
15
+ module Globus
16
+ # Client for interacting with the Globus API
17
+ class Client
18
+ include Singleton
19
+
20
+ class << self
21
+ # @param client_id [String] the client identifier registered with Globus
22
+ # @param client_secret [String] the client secret to authenticate with Globus
23
+ # @param uploads_directory [String] where to upload files
24
+ # @param transfer_endpoint_id [String] the transfer API endpoint ID supplied by Globus
25
+ # @param transfer_url [String] the transfer API URL
26
+ # @param auth_url [String] the authentication API URL
27
+ def configure(client_id:, client_secret:, uploads_directory:, transfer_endpoint_id:, transfer_url: default_transfer_url, auth_url: default_auth_url)
28
+ instance.config = OpenStruct.new(
29
+ token: Globus::Client::Authenticator.token(client_id, client_secret, auth_url),
30
+ uploads_directory:,
31
+ transfer_endpoint_id:,
32
+ transfer_url:,
33
+ auth_url:
34
+ )
35
+
36
+ self
37
+ end
38
+
39
+ delegate :mkdir, :config, to: :instance
40
+
41
+ def default_transfer_url
42
+ "https://transfer.api.globusonline.org"
43
+ end
44
+
45
+ def default_auth_url
46
+ "https://auth.globus.org"
47
+ end
48
+ end
49
+
50
+ attr_accessor :config
51
+
52
+ def mkdir(...)
53
+ endpoint = Globus::Client::Endpoint.new(config, ...)
54
+ endpoint.mkdir
55
+ endpoint.set_permissions
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,4 @@
1
+ module GlobusClient
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata CHANGED
@@ -1,14 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: globus_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Collier
8
- autorequire:
8
+ - Laura Wrubel
9
+ - Mike Giarlo
10
+ autorequire:
9
11
  bindir: exe
10
12
  cert_chain: []
11
- date: 2022-11-15 00:00:00.000000000 Z
13
+ date: 2022-11-21 00:00:00.000000000 Z
12
14
  dependencies:
13
15
  - !ruby/object:Gem::Dependency
14
16
  name: activesupport
@@ -31,7 +33,7 @@ dependencies:
31
33
  - !ruby/object:Gem::Version
32
34
  version: '8'
33
35
  - !ruby/object:Gem::Dependency
34
- name: config
36
+ name: faraday
35
37
  requirement: !ruby/object:Gem::Requirement
36
38
  requirements:
37
39
  - - ">="
@@ -45,7 +47,7 @@ dependencies:
45
47
  - !ruby/object:Gem::Version
46
48
  version: '0'
47
49
  - !ruby/object:Gem::Dependency
48
- name: faraday
50
+ name: zeitwerk
49
51
  requirement: !ruby/object:Gem::Requirement
50
52
  requirements:
51
53
  - - ">="
@@ -87,19 +89,19 @@ dependencies:
87
89
  - !ruby/object:Gem::Version
88
90
  version: '3.0'
89
91
  - !ruby/object:Gem::Dependency
90
- name: rubocop
92
+ name: standard
91
93
  requirement: !ruby/object:Gem::Requirement
92
94
  requirements:
93
- - - "~>"
95
+ - - ">="
94
96
  - !ruby/object:Gem::Version
95
- version: '1.21'
97
+ version: '0'
96
98
  type: :development
97
99
  prerelease: false
98
100
  version_requirements: !ruby/object:Gem::Requirement
99
101
  requirements:
100
- - - "~>"
102
+ - - ">="
101
103
  - !ruby/object:Gem::Version
102
- version: '1.21'
104
+ version: '0'
103
105
  - !ruby/object:Gem::Dependency
104
106
  name: rubocop-rspec
105
107
  requirement: !ruby/object:Gem::Requirement
@@ -145,10 +147,31 @@ dependencies:
145
147
  description: This provides API interaction with the Globus API
146
148
  email:
147
149
  - aaron.collier@stanford.edu
150
+ - lwrubel@stanford.edu
151
+ - mjgiarlo@stanford.edu
148
152
  executables: []
149
153
  extensions: []
150
154
  extra_rdoc_files: []
151
- files: []
155
+ files:
156
+ - ".autoupdate/postupdate"
157
+ - ".rspec"
158
+ - ".rubocop.yml"
159
+ - ".rubocop/custom.yml"
160
+ - ".rubocop_todo.yml"
161
+ - ".standard.yml"
162
+ - Gemfile
163
+ - Gemfile.lock
164
+ - LICENSE
165
+ - README.md
166
+ - Rakefile
167
+ - globus_client.gemspec
168
+ - lib/globus/client.rb
169
+ - lib/globus/client/authenticator.rb
170
+ - lib/globus/client/endpoint.rb
171
+ - lib/globus/client/identity.rb
172
+ - lib/globus/client/unexpected_response.rb
173
+ - lib/globus/client/version.rb
174
+ - sig/globus_client.rbs
152
175
  homepage: https://github.com/sul-dlss/globus_client
153
176
  licenses: []
154
177
  metadata:
@@ -156,7 +179,7 @@ metadata:
156
179
  source_code_uri: https://github.com/sul-dlss/globus_client
157
180
  changelog_uri: https://github.com/sul-dlss/globus_client/releases
158
181
  rubygems_mfa_required: 'true'
159
- post_install_message:
182
+ post_install_message:
160
183
  rdoc_options: []
161
184
  require_paths:
162
185
  - lib
@@ -171,8 +194,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
194
  - !ruby/object:Gem::Version
172
195
  version: '0'
173
196
  requirements: []
174
- rubygems_version: 3.3.3
175
- signing_key:
197
+ rubygems_version: 3.3.7
198
+ signing_key:
176
199
  specification_version: 4
177
200
  summary: Interface for interacting with the Globus API.
178
201
  test_files: []