archivesspace-client 0.4.1 → 0.5.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 +4 -4
- data/.github/workflows/ci.yml +7 -2
- data/.github/workflows/publish.yml +0 -1
- data/.ruby-version +1 -1
- data/README.md +135 -29
- data/archivesspace-client.gemspec +6 -7
- data/bin/console +1 -9
- data/examples/export.rb +11 -11
- data/examples/password_reset.rb +0 -1
- data/examples/repo_and_user.rb +8 -10
- data/examples/templates.rb +0 -1
- data/examples/test_connection.rb +13 -3
- data/examples/update_feed.rb +39 -0
- data/examples/user_groups.rb +8 -13
- data/lib/archivesspace/client/client.rb +22 -12
- data/lib/archivesspace/client/configuration.rb +16 -18
- data/lib/archivesspace/client/pagination.rb +1 -0
- data/lib/archivesspace/client/request.rb +10 -22
- data/lib/archivesspace/client/task.rb +16 -20
- data/lib/archivesspace/client/template.rb +4 -4
- data/lib/archivesspace/client/version.rb +1 -1
- data/lib/archivesspace/client.rb +4 -7
- data/spec/archivesspace/client_spec.rb +133 -18
- data/spec/archivesspace/templates_spec.rb +4 -4
- data/spec/fixtures/cassettes/login_failure.yml +37 -0
- data/spec/spec_helper.rb +1 -1
- metadata +27 -42
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 324a811c6e310286a30371cda14266b61f11570373aa20baf61b1f54b8e3c8d3
|
|
4
|
+
data.tar.gz: 319354d94ec1fb765a8a811f2ff8273c21342f40fa8e3a5e3c122b4b9af85b92
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1ecd05a580e11e19fd50db9b0f0d4ede6ff816d36d8789d50420a1d1275bf9247c5172b932f3ad9627e96655ce27f919d35e6737816650541615cf5efea22c95
|
|
7
|
+
data.tar.gz: 679be0bac6c9a81b685ed233e457d98670e00f834946f57d7ed46091bfd83040c0ee12d0e196bddd00a9bfb88fefc8b0c06170dfd294652b4322b958bfdac4df
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -3,15 +3,20 @@ on: [pull_request]
|
|
|
3
3
|
|
|
4
4
|
jobs:
|
|
5
5
|
tests:
|
|
6
|
-
name: Tests
|
|
6
|
+
name: Tests (Ruby ${{ matrix.ruby }})
|
|
7
7
|
runs-on: ubuntu-latest
|
|
8
|
+
strategy:
|
|
9
|
+
fail-fast: false
|
|
10
|
+
matrix:
|
|
11
|
+
ruby: ["3.4", "4.0"]
|
|
8
12
|
steps:
|
|
9
13
|
- name: Checkout code
|
|
10
|
-
uses: actions/checkout@
|
|
14
|
+
uses: actions/checkout@v4
|
|
11
15
|
|
|
12
16
|
- name: Setup Ruby and install gems
|
|
13
17
|
uses: ruby/setup-ruby@v1
|
|
14
18
|
with:
|
|
19
|
+
ruby-version: ${{ matrix.ruby }}
|
|
15
20
|
bundler-cache: true
|
|
16
21
|
|
|
17
22
|
- name: Lint
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
4.0.1
|
data/README.md
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ArchivesSpace Client
|
|
2
2
|
|
|
3
3
|
Interact with ArchivesSpace via the API.
|
|
4
4
|
|
|
5
|
+
<!-- TOC start (generated with https://github.com/derlin/bitdowntoc) -->
|
|
6
|
+
|
|
7
|
+
* [Installation](#installation)
|
|
8
|
+
* [Usage](#usage)
|
|
9
|
+
* [Configuring a client](#configuring-a-client)
|
|
10
|
+
* [Default configuration](#default-configuration)
|
|
11
|
+
* [Custom configuration, on the fly](#custom-configuration-on-the-fly)
|
|
12
|
+
* [Custom configuration, stored for use with CLI or console](#custom-configuration-stored-for-use-with-cli-or-console)
|
|
13
|
+
* [Making basic requests](#making-basic-requests)
|
|
14
|
+
* [Setting a repository context](#setting-a-repository-context)
|
|
15
|
+
* [Templates](#templates)
|
|
16
|
+
* [CLI](#cli)
|
|
17
|
+
* [Console usage](#console-usage)
|
|
18
|
+
* [Development](#development)
|
|
19
|
+
* [Publishing](#publishing)
|
|
20
|
+
* [Changelog](#changelog)
|
|
21
|
+
* [Contributing](#contributing)
|
|
22
|
+
* [License](#license)
|
|
23
|
+
|
|
24
|
+
<!-- TOC end -->
|
|
25
|
+
|
|
5
26
|
## Installation
|
|
6
27
|
|
|
7
28
|
Add this line to your application's Gemfile:
|
|
@@ -26,7 +47,9 @@ gem install archivesspace-client
|
|
|
26
47
|
|
|
27
48
|
See the examples directory for a range of use cases.
|
|
28
49
|
|
|
29
|
-
|
|
50
|
+
### Configuring a client
|
|
51
|
+
|
|
52
|
+
#### Default configuration
|
|
30
53
|
|
|
31
54
|
Create client with default settings (`localhost:8089`, `admin`, `admin`):
|
|
32
55
|
|
|
@@ -34,12 +57,11 @@ Create client with default settings (`localhost:8089`, `admin`, `admin`):
|
|
|
34
57
|
client = ArchivesSpace::Client.new.login
|
|
35
58
|
```
|
|
36
59
|
|
|
37
|
-
|
|
60
|
+
#### Custom configuration
|
|
38
61
|
|
|
39
62
|
```ruby
|
|
40
63
|
config = ArchivesSpace::Configuration.new({
|
|
41
|
-
base_uri: "https://archives.university.edu/api",
|
|
42
|
-
base_repo: "",
|
|
64
|
+
base_uri: "https://archives.university.edu/staff/api",
|
|
43
65
|
username: "admin",
|
|
44
66
|
password: "123456",
|
|
45
67
|
page_size: 50,
|
|
@@ -51,7 +73,32 @@ config = ArchivesSpace::Configuration.new({
|
|
|
51
73
|
client = ArchivesSpace::Client.new(config).login
|
|
52
74
|
```
|
|
53
75
|
|
|
54
|
-
|
|
76
|
+
#### Custom configuration, stored for use with CLI or console
|
|
77
|
+
|
|
78
|
+
Create a file containing JSON config data like:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"base_uri": "http://localhost:4567",
|
|
83
|
+
"username": "admin",
|
|
84
|
+
"password": "myverysecurepassword",
|
|
85
|
+
"page_size": 50,
|
|
86
|
+
"throttle": 0,
|
|
87
|
+
"timeout": 60,
|
|
88
|
+
"verify_ssl": false,
|
|
89
|
+
"debug": true
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The CLI and console commands will, by default, look for this stored config at `~/.asclientrc`,
|
|
94
|
+
|
|
95
|
+
However, you may also set a custom location for the file by setting an ASCLIENT_CFG environment variable. This is handy if you prefer to use [XDG Base Directory Specification](https://xdgbasedirectoryspecification.com/), or have other opinions about where such config should live:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
export ASCLIENT_CFG="$HOME/.config/archivesspace/client.json"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Making basic requests
|
|
55
102
|
|
|
56
103
|
The client responds to the standard request methods:
|
|
57
104
|
|
|
@@ -77,18 +124,46 @@ user = client.users.find { |user| user["username"] == "jdoe" }
|
|
|
77
124
|
See `pagination.rb` for endpoints that support record type methods such as
|
|
78
125
|
`client.digital_objects` etc.
|
|
79
126
|
|
|
80
|
-
|
|
127
|
+
### Setting a repository context
|
|
81
128
|
|
|
82
129
|
Use the `repository` method to add a repository scope to requests (this is optional).
|
|
83
130
|
|
|
131
|
+
Instead of doing:
|
|
132
|
+
|
|
84
133
|
```ruby
|
|
85
|
-
client.
|
|
86
|
-
|
|
134
|
+
client.get('repositories/2/digital_objects', query: {page: 1})
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
You can do:
|
|
138
|
+
|
|
139
|
+
```ruby
|
|
140
|
+
client.repository(2) do
|
|
141
|
+
client.get('digital_objects', query: {page: 1})
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# now back in the global scope
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Scopes restore the previous context on exit (even if the block raises) and can
|
|
148
|
+
be nested:
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
client.repository(2) do
|
|
152
|
+
client.repository(3) do
|
|
153
|
+
client.resources # scoped to repo 3
|
|
154
|
+
end
|
|
155
|
+
client.resources # back to repo 2
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# now back in the global scope
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
You can also set the scope persistently (without a block) and clear it later:
|
|
87
162
|
|
|
88
|
-
|
|
89
|
-
client.repository(
|
|
90
|
-
|
|
91
|
-
client.use_global_repository
|
|
163
|
+
```ruby
|
|
164
|
+
client.repository(2)
|
|
165
|
+
client.resources
|
|
166
|
+
client.use_global_repository # or: client.repository(nil)
|
|
92
167
|
```
|
|
93
168
|
|
|
94
169
|
## Templates
|
|
@@ -124,26 +199,40 @@ To view available templates use: `ArchivesSpace::Template.list`
|
|
|
124
199
|
|
|
125
200
|
## CLI
|
|
126
201
|
|
|
127
|
-
Create
|
|
202
|
+
Create a stored custom configuration to be used with the CLI as described above.
|
|
128
203
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
"throttle": 0,
|
|
137
|
-
"timeout": 60,
|
|
138
|
-
"verify_ssl": false
|
|
139
|
-
}
|
|
204
|
+
If you installed this client as a gem via the `gem install archivesspace-client` command, you should be able to use the `asclient` command directly.
|
|
205
|
+
|
|
206
|
+
If entering `asclient` in your terminal returns an error, you will need to use the CLI from within this repository:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
cd path/to/archivesspace-client
|
|
210
|
+
./exe/asclient
|
|
140
211
|
```
|
|
141
212
|
|
|
142
|
-
|
|
213
|
+
The `asclient` command is self-documenting and will show you information about the currently supported commands.
|
|
214
|
+
|
|
215
|
+
To get more detailed usage info on a command:
|
|
143
216
|
|
|
144
217
|
```bash
|
|
145
|
-
|
|
146
|
-
|
|
218
|
+
asclient exec -h
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Console usage
|
|
222
|
+
|
|
223
|
+
Loading this application in console allows you to play around with its functionality interactively.
|
|
224
|
+
|
|
225
|
+
Create a stored custom configuration to be used with the console as described above. Then:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
cd path/to/archivesspace-client
|
|
229
|
+
./bin/console
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
An IRB session opens. Entering the following should give you the backend version of the ArchivesSpace instance your stored custom config points to:
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
@client.backend_version
|
|
147
236
|
```
|
|
148
237
|
|
|
149
238
|
## Development
|
|
@@ -169,9 +258,26 @@ bundle exec rake
|
|
|
169
258
|
When an updated version (`lib/archivesspace/client/version.rb`) is merged into the
|
|
170
259
|
main/master branch a new release will be built and published.
|
|
171
260
|
|
|
261
|
+
## Changelog
|
|
262
|
+
|
|
263
|
+
### 0.5.0
|
|
264
|
+
|
|
265
|
+
Breaking changes:
|
|
266
|
+
|
|
267
|
+
* Removed the `base_repo` configuration option. Use `client.repository(id)` to
|
|
268
|
+
scope requests to a repository instead, either persistently or with a
|
|
269
|
+
block that auto-restores the previous scope.
|
|
270
|
+
* `client.repository(id)` with a block now saves and restores the previous
|
|
271
|
+
context (including when nested or when the block raises), instead of always
|
|
272
|
+
resetting to the global scope.
|
|
273
|
+
* Login failure now raises `ArchivesSpace::AuthenticationError` (was
|
|
274
|
+
`ConnectionError`). `ConnectionError` has been removed.
|
|
275
|
+
* `Client.new` raises `ArchivesSpace::ConfigurationError` (was `RuntimeError`)
|
|
276
|
+
when given a non-`Configuration` argument.
|
|
277
|
+
|
|
172
278
|
## Contributing
|
|
173
279
|
|
|
174
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/lyrasis/archivesspace-client
|
|
280
|
+
Bug reports and pull requests are welcome on GitHub at <https://github.com/lyrasis/archivesspace-client>.
|
|
175
281
|
|
|
176
282
|
## License
|
|
177
283
|
|
|
@@ -23,15 +23,14 @@ Gem::Specification.new do |spec|
|
|
|
23
23
|
spec.add_development_dependency "capybara_discoball", "~> 0.1.0"
|
|
24
24
|
spec.add_development_dependency "json_spec", "~> 1.1", ">= 1.1.5"
|
|
25
25
|
spec.add_development_dependency "rake", "~> 13.0"
|
|
26
|
-
spec.add_development_dependency "rspec", "3.
|
|
27
|
-
spec.add_development_dependency "rubocop", "1.
|
|
28
|
-
spec.add_development_dependency "standard", "1.
|
|
29
|
-
spec.add_development_dependency "vcr", "6.
|
|
30
|
-
spec.add_development_dependency "webmock", "3.
|
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.13"
|
|
27
|
+
spec.add_development_dependency "rubocop", "~> 1.72"
|
|
28
|
+
spec.add_development_dependency "standard", "~> 1.44"
|
|
29
|
+
spec.add_development_dependency "vcr", "~> 6.3"
|
|
30
|
+
spec.add_development_dependency "webmock", "~> 3.24"
|
|
31
31
|
|
|
32
32
|
spec.add_dependency "dry-cli", "~> 0.7"
|
|
33
33
|
spec.add_dependency "httparty", "~> 0.14"
|
|
34
34
|
spec.add_dependency "json", "~> 2.0"
|
|
35
|
-
spec.add_dependency "
|
|
36
|
-
spec.add_dependency "jbuilder", "~> 2.11.5"
|
|
35
|
+
spec.add_dependency "jbuilder", "~> 2.12"
|
|
37
36
|
end
|
data/bin/console
CHANGED
|
@@ -5,15 +5,7 @@ require "bundler/setup"
|
|
|
5
5
|
require "archivesspace/client"
|
|
6
6
|
|
|
7
7
|
config = ArchivesSpace::Configuration.new(
|
|
8
|
-
|
|
9
|
-
base_uri: "https://test.archivesspace.org/staff/api",
|
|
10
|
-
base_repo: "",
|
|
11
|
-
username: "admin",
|
|
12
|
-
password: "admin",
|
|
13
|
-
page_size: 50,
|
|
14
|
-
throttle: 0,
|
|
15
|
-
verify_ssl: false
|
|
16
|
-
}
|
|
8
|
+
ArchivesSpace::Client::CLI.find_config
|
|
17
9
|
)
|
|
18
10
|
@client = ArchivesSpace::Client.new(config).login
|
|
19
11
|
|
data/examples/export.rb
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
4
|
-
require "awesome_print"
|
|
5
4
|
require "archivesspace/client"
|
|
5
|
+
require "nokogiri"
|
|
6
6
|
|
|
7
7
|
# official sandbox
|
|
8
8
|
config = ArchivesSpace::Configuration.new(
|
|
9
9
|
{
|
|
10
10
|
base_uri: "https://test.archivesspace.org/staff/api",
|
|
11
|
-
base_repo: "",
|
|
12
11
|
username: "admin",
|
|
13
12
|
password: "admin",
|
|
14
13
|
page_size: 50,
|
|
@@ -19,17 +18,18 @@ config = ArchivesSpace::Configuration.new(
|
|
|
19
18
|
|
|
20
19
|
client = ArchivesSpace::Client.new(config).login
|
|
21
20
|
client.config.throttle = 0.5
|
|
22
|
-
client.config.base_repo = "repositories/2"
|
|
23
21
|
|
|
24
22
|
begin
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
client.repository 2 do
|
|
24
|
+
# date -d '2021-02-01 00:00:00' +'%s' # 1612166400
|
|
25
|
+
client.resources(query: {modified_since: "1612166400"}).each do |resource|
|
|
26
|
+
# for now we are just printing ...
|
|
27
|
+
# but you would actually write to a zip file or whatever
|
|
28
|
+
id = resource["uri"].split("/")[-1]
|
|
29
|
+
opts = {include_unpublished: false}
|
|
30
|
+
response = client.get("resource_descriptions/#{id}.xml", opts)
|
|
31
|
+
puts Nokogiri::XML(response.body).to_xml
|
|
32
|
+
end
|
|
33
33
|
end
|
|
34
34
|
rescue ArchivesSpace::RequestError => e
|
|
35
35
|
puts e.message
|
data/examples/password_reset.rb
CHANGED
data/examples/repo_and_user.rb
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
4
|
-
require "awesome_print"
|
|
5
4
|
require "archivesspace/client"
|
|
6
5
|
|
|
7
6
|
# official sandbox
|
|
8
7
|
config = ArchivesSpace::Configuration.new(
|
|
9
8
|
{
|
|
10
|
-
base_uri: "https://sandbox.archivesspace.org/api",
|
|
11
|
-
base_repo: "",
|
|
9
|
+
base_uri: "https://sandbox.archivesspace.org/staff/api",
|
|
12
10
|
username: "admin",
|
|
13
11
|
password: "admin",
|
|
14
12
|
page_size: 50,
|
|
@@ -19,7 +17,7 @@ config = ArchivesSpace::Configuration.new(
|
|
|
19
17
|
|
|
20
18
|
client = ArchivesSpace::Client.new(config).login
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
puts ArchivesSpace::Template.list # view available templates
|
|
23
21
|
|
|
24
22
|
repo_data = {
|
|
25
23
|
repo_code: "XYZ",
|
|
@@ -40,20 +38,20 @@ begin
|
|
|
40
38
|
response = client.post("/repositories/with_agent", repository)
|
|
41
39
|
if response.result.success?
|
|
42
40
|
repository = client.repositories.find { |r| r["repo_code"] == "XYZ" }
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
puts repository
|
|
42
|
+
puts client.delete(repository["uri"])
|
|
45
43
|
else
|
|
46
|
-
|
|
44
|
+
puts response.parsed
|
|
47
45
|
end
|
|
48
46
|
|
|
49
47
|
user = ArchivesSpace::Template.process("user.json.erb", user_data)
|
|
50
48
|
response = client.post("users", user, {password: user_password})
|
|
51
49
|
if response.result.success?
|
|
52
50
|
user = client.users.find { |r| r["username"] == "lmessi" }
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
puts user
|
|
52
|
+
puts client.delete(user["uri"]).inspect
|
|
55
53
|
else
|
|
56
|
-
|
|
54
|
+
puts response.parsed
|
|
57
55
|
end
|
|
58
56
|
rescue ArchivesSpace::RequestError => e
|
|
59
57
|
puts e.message
|
data/examples/templates.rb
CHANGED
data/examples/test_connection.rb
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
4
|
-
require "awesome_print"
|
|
5
4
|
require "archivesspace/client"
|
|
6
5
|
|
|
7
6
|
# official sandbox
|
|
8
7
|
config = ArchivesSpace::Configuration.new(
|
|
9
8
|
{
|
|
10
|
-
base_uri: "https://
|
|
11
|
-
base_repo: "",
|
|
9
|
+
base_uri: "https://test.archivesspace.org/staff/api",
|
|
12
10
|
username: "admin",
|
|
13
11
|
password: "admin",
|
|
14
12
|
page_size: 50,
|
|
@@ -18,4 +16,16 @@ config = ArchivesSpace::Configuration.new(
|
|
|
18
16
|
)
|
|
19
17
|
|
|
20
18
|
client = ArchivesSpace::Client.new(config).login
|
|
19
|
+
|
|
20
|
+
# globally scoped
|
|
21
21
|
puts client.get("version").body
|
|
22
|
+
puts client.get("repositories").body
|
|
23
|
+
puts client.all("users").map { |u| u["username"] }.to_a
|
|
24
|
+
|
|
25
|
+
# repo scoped
|
|
26
|
+
client.repository 2 do
|
|
27
|
+
puts client.get("accessions", query: {page: 1}).parsed["results"].map { |a| a["uri"] }.to_a
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# globally scoped, full path arg
|
|
31
|
+
puts client.get("repositories/2/resources", query: {all_ids: true}).body
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
4
|
+
require "archivesspace/client"
|
|
5
|
+
|
|
6
|
+
config = ArchivesSpace::Configuration.new(
|
|
7
|
+
{
|
|
8
|
+
base_uri: "https://test.archivesspace.org/staff/api",
|
|
9
|
+
username: "admin",
|
|
10
|
+
password: "admin",
|
|
11
|
+
page_size: 50,
|
|
12
|
+
throttle: 0,
|
|
13
|
+
verify_ssl: false
|
|
14
|
+
}
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
client = ArchivesSpace::Client.new(config).login
|
|
18
|
+
response = client.get("update-feed")
|
|
19
|
+
last_sequence = response.parsed[0]["sequence"] # get initial sequence value
|
|
20
|
+
|
|
21
|
+
# This is an example only, would also need to handle session/token expiration
|
|
22
|
+
loop do
|
|
23
|
+
puts "Using sequence: #{last_sequence}"
|
|
24
|
+
begin
|
|
25
|
+
response = client.get("update-feed", query: {last_sequence: last_sequence})
|
|
26
|
+
if response.result.success?
|
|
27
|
+
last_sequence = response.parsed.last["sequence"]
|
|
28
|
+
# do something with the response
|
|
29
|
+
puts response.parsed.to_json
|
|
30
|
+
end
|
|
31
|
+
rescue Net::ReadTimeout
|
|
32
|
+
# this is ok if no updates are made within the last 60 seconds
|
|
33
|
+
# (well, as defined by the timeout in client/AppConfig)
|
|
34
|
+
rescue => e
|
|
35
|
+
# some other kind of error occurred
|
|
36
|
+
puts e.message
|
|
37
|
+
break # or handle it in some other way
|
|
38
|
+
end
|
|
39
|
+
end
|
data/examples/user_groups.rb
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
4
|
-
require "awesome_print"
|
|
5
4
|
require "archivesspace/client"
|
|
6
5
|
|
|
7
6
|
# official sandbox
|
|
8
7
|
config = ArchivesSpace::Configuration.new(
|
|
9
8
|
{
|
|
10
|
-
base_uri: "https://sandbox.archivesspace.org/api",
|
|
11
|
-
base_repo: "",
|
|
9
|
+
base_uri: "https://sandbox.archivesspace.org/staff/api",
|
|
12
10
|
username: "admin",
|
|
13
11
|
password: "admin",
|
|
14
12
|
page_size: 50,
|
|
@@ -19,26 +17,23 @@ config = ArchivesSpace::Configuration.new(
|
|
|
19
17
|
|
|
20
18
|
client = ArchivesSpace::Client.new(config).login
|
|
21
19
|
|
|
22
|
-
user_data = {
|
|
20
|
+
user_data = ArchivesSpace::Template.process("user.json.erb", {
|
|
23
21
|
username: "bde",
|
|
24
22
|
name: "BDE",
|
|
25
23
|
is_admin: false
|
|
26
|
-
}
|
|
24
|
+
})
|
|
27
25
|
|
|
28
|
-
client.post(
|
|
29
|
-
"users",
|
|
30
|
-
ArchivesSpace::Template.process("user.json.erb", user_data),
|
|
31
|
-
{password: "123456"}
|
|
32
|
-
)
|
|
26
|
+
client.post("users", user_data, {password: "123456"})
|
|
33
27
|
|
|
34
28
|
users_with_roles = {
|
|
35
29
|
"bde" => ["repository-basic-data-entry"]
|
|
36
30
|
}
|
|
37
31
|
|
|
38
32
|
begin
|
|
39
|
-
client.
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
client.repository 2 do
|
|
34
|
+
results = client.group_user_assignment users_with_roles
|
|
35
|
+
puts results.map(&:parsed)
|
|
36
|
+
end
|
|
42
37
|
rescue ArchivesSpace::RequestError => e
|
|
43
38
|
puts e.message
|
|
44
39
|
end
|
|
@@ -4,15 +4,20 @@ module ArchivesSpace
|
|
|
4
4
|
class Client
|
|
5
5
|
include Pagination
|
|
6
6
|
include Task
|
|
7
|
+
|
|
7
8
|
attr_accessor :token
|
|
8
|
-
attr_reader :config
|
|
9
|
+
attr_reader :config, :context
|
|
9
10
|
|
|
10
11
|
NAME = "ArchivesSpaceClient"
|
|
12
|
+
TOKEN = "X-ArchivesSpace-Session"
|
|
11
13
|
|
|
12
14
|
def initialize(config = Configuration.new)
|
|
13
|
-
|
|
15
|
+
unless config.is_a? ArchivesSpace::Configuration
|
|
16
|
+
raise ConfigurationError, "expected ArchivesSpace::Configuration, got #{config.class}"
|
|
17
|
+
end
|
|
14
18
|
|
|
15
19
|
@config = config
|
|
20
|
+
@context = nil
|
|
16
21
|
@token = nil
|
|
17
22
|
end
|
|
18
23
|
|
|
@@ -38,31 +43,36 @@ module ArchivesSpace
|
|
|
38
43
|
|
|
39
44
|
# Scoping requests
|
|
40
45
|
def repository(id)
|
|
41
|
-
if id.nil?
|
|
42
|
-
use_global_repository
|
|
43
|
-
return
|
|
44
|
-
end
|
|
46
|
+
return use_global_repository if id.nil?
|
|
45
47
|
|
|
46
48
|
begin
|
|
47
49
|
Integer(id)
|
|
48
|
-
rescue
|
|
50
|
+
rescue ArgumentError, TypeError
|
|
49
51
|
raise RepositoryIdError, "Invalid Repository id: #{id}"
|
|
50
52
|
end
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
new_context = "repositories/#{id}"
|
|
55
|
+
return @context = new_context unless block_given?
|
|
56
|
+
|
|
57
|
+
previous = @context
|
|
58
|
+
@context = new_context
|
|
59
|
+
begin
|
|
60
|
+
yield
|
|
61
|
+
ensure
|
|
62
|
+
@context = previous
|
|
63
|
+
end
|
|
53
64
|
end
|
|
54
65
|
|
|
55
66
|
def use_global_repository
|
|
56
|
-
@
|
|
67
|
+
@context = nil
|
|
57
68
|
end
|
|
58
69
|
|
|
59
70
|
private
|
|
60
71
|
|
|
61
72
|
def request(method, path, options = {})
|
|
62
73
|
sleep config.throttle
|
|
63
|
-
options[:headers] = {
|
|
64
|
-
|
|
65
|
-
Response.new result
|
|
74
|
+
options[:headers] = {TOKEN => token} if token
|
|
75
|
+
Request.new(context, config, method, path, options).execute
|
|
66
76
|
end
|
|
67
77
|
end
|
|
68
78
|
end
|
|
@@ -2,27 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
module ArchivesSpace
|
|
4
4
|
class Configuration
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
5
|
+
attr_accessor :base_uri, :debug, :username, :password,
|
|
6
|
+
:page_size, :throttle, :timeout, :verify_ssl
|
|
7
|
+
|
|
8
|
+
DEFAULTS = {
|
|
9
|
+
base_uri: "http://localhost:8089",
|
|
10
|
+
debug: false,
|
|
11
|
+
username: "admin",
|
|
12
|
+
password: "admin",
|
|
13
|
+
page_size: 50,
|
|
14
|
+
throttle: 0,
|
|
15
|
+
timeout: 60,
|
|
16
|
+
verify_ssl: true
|
|
17
|
+
}.freeze
|
|
18
18
|
|
|
19
19
|
def initialize(settings = {})
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
next unless defaults.key?(property)
|
|
20
|
+
DEFAULTS.merge(settings).each do |property, value|
|
|
21
|
+
next unless DEFAULTS.key?(property)
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
self.class.send(:attr_accessor, property)
|
|
23
|
+
send(:"#{property}=", value)
|
|
26
24
|
end
|
|
27
25
|
end
|
|
28
26
|
end
|
|
@@ -3,44 +3,32 @@
|
|
|
3
3
|
module ArchivesSpace
|
|
4
4
|
class Request
|
|
5
5
|
include HTTParty
|
|
6
|
+
|
|
6
7
|
attr_reader :config, :headers, :method, :path, :options
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
headers = {
|
|
10
|
-
delete: {},
|
|
11
|
-
get: {},
|
|
12
|
-
post: {
|
|
13
|
-
"Content-Type" => "application/json",
|
|
14
|
-
"Content-Length" => "nnnn"
|
|
15
|
-
},
|
|
16
|
-
put: {
|
|
17
|
-
"Content-Type" => "application/json",
|
|
18
|
-
"Content-Length" => "nnnn"
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
headers[method]
|
|
22
|
-
end
|
|
9
|
+
DEFAULT_HEADERS = {"Content-Type" => "application/json"}.freeze
|
|
23
10
|
|
|
24
|
-
def initialize(config, method = "GET", path = "", options = {})
|
|
11
|
+
def initialize(context, config, method = "GET", path = "", options = {})
|
|
25
12
|
@config = config
|
|
13
|
+
|
|
26
14
|
@method = method.downcase.to_sym
|
|
27
15
|
@path = path.gsub(%r{^/+}, "")
|
|
16
|
+
|
|
28
17
|
@options = options
|
|
29
|
-
|
|
30
|
-
|
|
18
|
+
|
|
19
|
+
@options[:headers] = DEFAULT_HEADERS.merge(@options.fetch(:headers, {}))
|
|
31
20
|
@options[:headers]["User-Agent"] = "#{Client::NAME}/#{Client::VERSION}"
|
|
21
|
+
|
|
32
22
|
@options[:verify] = config.verify_ssl
|
|
33
23
|
@options[:timeout] = config.timeout
|
|
34
24
|
@options[:query] = {} unless options.key? :query
|
|
35
25
|
|
|
36
26
|
self.class.debug_output($stdout) if @config.debug
|
|
37
|
-
|
|
38
|
-
base_uri = config.base_repo&.length&.positive? ? File.join(config.base_uri, config.base_repo) : config.base_uri
|
|
39
|
-
self.class.base_uri base_uri
|
|
27
|
+
self.class.base_uri context ? "#{config.base_uri}/#{context}" : config.base_uri
|
|
40
28
|
end
|
|
41
29
|
|
|
42
30
|
def execute
|
|
43
|
-
self.class.send
|
|
31
|
+
Response.new(self.class.send(method, "/#{path}", options))
|
|
44
32
|
end
|
|
45
33
|
end
|
|
46
34
|
end
|
|
@@ -3,10 +3,6 @@
|
|
|
3
3
|
module ArchivesSpace
|
|
4
4
|
# Perform specific API tasks
|
|
5
5
|
module Task
|
|
6
|
-
# def batch_import(payload, params = {})
|
|
7
|
-
# # TODO: create "batch_import", payload, params
|
|
8
|
-
# end
|
|
9
|
-
|
|
10
6
|
def group_user_assignment(users_with_roles)
|
|
11
7
|
updated = []
|
|
12
8
|
groups.each do |group|
|
|
@@ -29,7 +25,7 @@ module ArchivesSpace
|
|
|
29
25
|
|
|
30
26
|
next unless update
|
|
31
27
|
|
|
32
|
-
response = post("/groups/#{uri_to_id(group["uri"])}", group
|
|
28
|
+
response = post("/groups/#{uri_to_id(group["uri"])}", group)
|
|
33
29
|
updated << response
|
|
34
30
|
end
|
|
35
31
|
updated
|
|
@@ -38,29 +34,29 @@ module ArchivesSpace
|
|
|
38
34
|
def login
|
|
39
35
|
username = config.username
|
|
40
36
|
password = config.password
|
|
41
|
-
base_repo = config.base_repo
|
|
42
|
-
use_global_repository # ensure we're in the global scope to login
|
|
43
|
-
result = request("POST", "/users/#{username}/login", {query: {password: password}})
|
|
44
|
-
unless result.parsed["session"]
|
|
45
|
-
raise ConnectionError, "API client login failed as user [#{username}], check username and password are correct"
|
|
46
|
-
end
|
|
47
37
|
|
|
48
|
-
|
|
49
|
-
@
|
|
50
|
-
|
|
38
|
+
previous_context = @context
|
|
39
|
+
@context = nil
|
|
40
|
+
begin
|
|
41
|
+
result = request("POST", "/users/#{username}/login", {query: {password: password}})
|
|
42
|
+
unless result.parsed["session"]
|
|
43
|
+
raise AuthenticationError, "Login failed as user [#{username}] (status #{result.status_code}); check username and password"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
@token = result.parsed["session"]
|
|
47
|
+
self
|
|
48
|
+
ensure
|
|
49
|
+
@context = previous_context
|
|
50
|
+
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def password_reset(username, password)
|
|
54
54
|
user = all("users").find { |u| u["username"] == username }
|
|
55
|
-
raise RequestError,
|
|
55
|
+
raise RequestError, "User not found: #{username}" unless user
|
|
56
56
|
|
|
57
|
-
post(user["uri"], user
|
|
57
|
+
post(user["uri"], user, {password: password})
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
# def search(params)
|
|
61
|
-
# # TODO: get "search", params
|
|
62
|
-
# end
|
|
63
|
-
|
|
64
60
|
private
|
|
65
61
|
|
|
66
62
|
def uri_to_id(uri)
|
|
@@ -7,7 +7,7 @@ module ArchivesSpace
|
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def self.process(template, data)
|
|
10
|
-
processor = File.extname(template).delete(".").
|
|
10
|
+
processor = File.extname(template).delete(".").capitalize
|
|
11
11
|
processor = Object.const_get("ArchivesSpace::Template::#{processor}")
|
|
12
12
|
processor.new(template, data).process
|
|
13
13
|
end
|
|
@@ -50,7 +50,7 @@ module ArchivesSpace
|
|
|
50
50
|
def process
|
|
51
51
|
t = ERB.new(read_template)
|
|
52
52
|
r = t.result(binding).squeeze("\n")
|
|
53
|
-
JSON.parse(r)
|
|
53
|
+
JSON.parse(r)
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
|
|
@@ -60,9 +60,9 @@ module ArchivesSpace
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
def process
|
|
63
|
-
::Jbuilder.
|
|
63
|
+
::Jbuilder.new do |json|
|
|
64
64
|
eval(read_template, binding) # standard:disable Security/Eval
|
|
65
|
-
end
|
|
65
|
+
end.attributes!
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
end
|
data/lib/archivesspace/client.rb
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
require "dry/cli"
|
|
4
4
|
require "httparty"
|
|
5
5
|
require "json"
|
|
6
|
-
require "nokogiri"
|
|
7
6
|
require "jbuilder"
|
|
8
7
|
|
|
9
8
|
# mixins required first
|
|
@@ -23,13 +22,11 @@ require "archivesspace/client/cli/version"
|
|
|
23
22
|
require "archivesspace/client/cli" # load the registry last
|
|
24
23
|
|
|
25
24
|
module ArchivesSpace
|
|
26
|
-
class
|
|
25
|
+
class AuthenticationError < StandardError; end
|
|
27
26
|
|
|
28
|
-
class
|
|
27
|
+
class ConfigurationError < StandardError; end
|
|
29
28
|
|
|
30
|
-
class RepositoryIdError <
|
|
29
|
+
class RepositoryIdError < StandardError; end
|
|
31
30
|
|
|
32
|
-
class
|
|
33
|
-
|
|
34
|
-
class RequestError < RuntimeError; end
|
|
31
|
+
class RequestError < StandardError; end
|
|
35
32
|
end
|
|
@@ -11,7 +11,7 @@ describe ArchivesSpace::Client do
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
it "will raise an error if supplied configuration is of invalid type" do
|
|
14
|
-
expect { ArchivesSpace::Client.new({base_uri: CUSTOM_BASE_URI}) }.to raise_error(
|
|
14
|
+
expect { ArchivesSpace::Client.new({base_uri: CUSTOM_BASE_URI}) }.to raise_error(ArchivesSpace::ConfigurationError)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
it "will allow a configuration object to be provided" do
|
|
@@ -20,15 +20,86 @@ describe ArchivesSpace::Client do
|
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
describe "Login" do
|
|
24
|
+
it "sends the login request at global scope even when a repo context is set" do
|
|
25
|
+
client.repository 2
|
|
26
|
+
expect(ArchivesSpace::Request).to receive(:new)
|
|
27
|
+
.with(nil, client.config, "POST", "/users/admin/login", anything)
|
|
28
|
+
.and_wrap_original do |_orig, *_args|
|
|
29
|
+
double("request", execute: double("response", parsed: {"session" => "token"}, status_code: 200))
|
|
30
|
+
end
|
|
31
|
+
client.login
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "restores the previous repo context after login" do
|
|
35
|
+
client.repository 2
|
|
36
|
+
allow(ArchivesSpace::Request).to receive(:new).and_return(
|
|
37
|
+
double("request", execute: double("response", parsed: {"session" => "token"}, status_code: 200))
|
|
38
|
+
)
|
|
39
|
+
client.login
|
|
40
|
+
expect(client.context).to eq "repositories/2"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "raises AuthenticationError and restores context when credentials are rejected" do
|
|
44
|
+
client.repository 2
|
|
45
|
+
allow(ArchivesSpace::Request).to receive(:new).and_return(
|
|
46
|
+
double("request", execute: double("response", parsed: {}, status_code: 403))
|
|
47
|
+
)
|
|
48
|
+
expect { client.login }.to raise_error(ArchivesSpace::AuthenticationError, /status 403/)
|
|
49
|
+
expect(client.context).to eq "repositories/2"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "raises AuthenticationError for a real 403 response (VCR)" do
|
|
53
|
+
bad_client = ArchivesSpace::Client.new(
|
|
54
|
+
ArchivesSpace::Configuration.new(password: "wrong")
|
|
55
|
+
)
|
|
56
|
+
VCR.use_cassette("login_failure") do
|
|
57
|
+
expect { bad_client.login }.to raise_error(
|
|
58
|
+
ArchivesSpace::AuthenticationError, /admin.*status 403/
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe "Pagination" do
|
|
65
|
+
it "will have a method for defined paginated record types" do
|
|
66
|
+
ArchivesSpace::Pagination::ENDPOINTS.each do |e|
|
|
67
|
+
next if e.match?("/")
|
|
68
|
+
|
|
69
|
+
expect(client.respond_to?(e.to_sym)).to be true
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "will have a method for defined paginated record types with multipart path" do
|
|
74
|
+
expect(client.respond_to?(:people)).to be true
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "will pass page_size from configuration to the query" do
|
|
78
|
+
response = double("response", parsed: {"results" => []})
|
|
79
|
+
allow(client).to receive(:get).and_return(response)
|
|
80
|
+
client.all("resources").first
|
|
81
|
+
expect(client).to have_received(:get).with("resources", hash_including(query: hash_including(page_size: 50)))
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe "Password reset" do
|
|
86
|
+
it "will raise an error if the user is not found" do
|
|
87
|
+
allow(client).to receive(:all).with("users").and_return([].lazy)
|
|
88
|
+
expect { client.password_reset("nonexistent", "newpass") }.to raise_error(
|
|
89
|
+
ArchivesSpace::RequestError, "User not found: nonexistent"
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
23
94
|
describe "Repository scoping" do
|
|
24
|
-
it "will set the
|
|
95
|
+
it "will set the context with an integer id" do
|
|
25
96
|
client.repository 2
|
|
26
|
-
expect(client.
|
|
97
|
+
expect(client.context).to eq "repositories/2"
|
|
27
98
|
end
|
|
28
99
|
|
|
29
|
-
it "will set the
|
|
100
|
+
it "will set the context with a string id cast to integer" do
|
|
30
101
|
client.repository "2"
|
|
31
|
-
expect(client.
|
|
102
|
+
expect(client.context).to eq "repositories/2"
|
|
32
103
|
end
|
|
33
104
|
|
|
34
105
|
it "will fail if the id cannot be cast to integer" do
|
|
@@ -37,37 +108,81 @@ describe ArchivesSpace::Client do
|
|
|
37
108
|
)
|
|
38
109
|
end
|
|
39
110
|
|
|
40
|
-
it "will
|
|
111
|
+
it "will fail if the id is not a valid type" do
|
|
112
|
+
expect { client.repository([]) }.to raise_error(
|
|
113
|
+
ArchivesSpace::RepositoryIdError
|
|
114
|
+
)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "will clear the context when passed nil" do
|
|
41
118
|
client.repository 2
|
|
42
119
|
client.repository nil
|
|
43
|
-
expect(client.
|
|
120
|
+
expect(client.context).to be_nil
|
|
44
121
|
end
|
|
45
122
|
|
|
46
|
-
it "will
|
|
123
|
+
it "will clear the context when use_global_repository is called" do
|
|
47
124
|
client.repository 2
|
|
48
125
|
client.use_global_repository
|
|
49
|
-
expect(client.
|
|
126
|
+
expect(client.context).to be_nil
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "scopes the context to a block and restores afterwards" do
|
|
130
|
+
client.repository(2) do
|
|
131
|
+
expect(client.context).to eq "repositories/2"
|
|
132
|
+
end
|
|
133
|
+
expect(client.context).to be_nil
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "restores the previous context when nested" do
|
|
137
|
+
client.repository 2
|
|
138
|
+
client.repository(3) do
|
|
139
|
+
expect(client.context).to eq "repositories/3"
|
|
140
|
+
end
|
|
141
|
+
expect(client.context).to eq "repositories/2"
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "restores the context even if the block raises" do
|
|
145
|
+
expect { client.repository(2) { raise "boom" } }.to raise_error("boom")
|
|
146
|
+
expect(client.context).to be_nil
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it "does not rebrand ArgumentError raised from within the block" do
|
|
150
|
+
expect {
|
|
151
|
+
client.repository(2) { raise ArgumentError, "from caller" }
|
|
152
|
+
}.to raise_error(ArgumentError, "from caller")
|
|
50
153
|
end
|
|
51
154
|
end
|
|
52
155
|
|
|
53
156
|
describe "Requests" do
|
|
54
157
|
it "will have an identifiable user agent" do
|
|
55
|
-
request = ArchivesSpace::Request.new(client.config)
|
|
158
|
+
request = ArchivesSpace::Request.new(nil, client.config)
|
|
56
159
|
expect(request.options[:headers]["User-Agent"]).to eq "#{ArchivesSpace::Client::NAME}/#{ArchivesSpace::Client::VERSION}"
|
|
57
160
|
end
|
|
58
161
|
end
|
|
59
162
|
|
|
60
|
-
describe "
|
|
61
|
-
|
|
62
|
-
ArchivesSpace::Pagination::ENDPOINTS.each do |e|
|
|
63
|
-
next if e.match?("/")
|
|
163
|
+
describe "URL construction" do
|
|
164
|
+
let(:config) { ArchivesSpace::Configuration.new(base_uri: "http://localhost:8089") }
|
|
64
165
|
|
|
65
|
-
|
|
66
|
-
|
|
166
|
+
it "uses the bare base_uri when context is nil" do
|
|
167
|
+
ArchivesSpace::Request.new(nil, config, "GET", "repositories")
|
|
168
|
+
expect(ArchivesSpace::Request.base_uri).to eq "http://localhost:8089"
|
|
67
169
|
end
|
|
68
170
|
|
|
69
|
-
it "
|
|
70
|
-
|
|
171
|
+
it "appends a repository context to the base_uri" do
|
|
172
|
+
ArchivesSpace::Request.new("repositories/2", config, "GET", "resources")
|
|
173
|
+
expect(ArchivesSpace::Request.base_uri).to eq "http://localhost:8089/repositories/2"
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it "preserves a path prefix in base_uri when context is nil" do
|
|
177
|
+
config.base_uri = "https://example.org/staff/api"
|
|
178
|
+
ArchivesSpace::Request.new(nil, config, "GET", "repositories")
|
|
179
|
+
expect(ArchivesSpace::Request.base_uri).to eq "https://example.org/staff/api"
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
it "preserves a path prefix in base_uri when scoped to a repository" do
|
|
183
|
+
config.base_uri = "https://example.org/staff/api"
|
|
184
|
+
ArchivesSpace::Request.new("repositories/2", config, "GET", "resources")
|
|
185
|
+
expect(ArchivesSpace::Request.base_uri).to eq "https://example.org/staff/api/repositories/2"
|
|
71
186
|
end
|
|
72
187
|
end
|
|
73
188
|
|
|
@@ -21,14 +21,14 @@ describe ArchivesSpace::Template do
|
|
|
21
21
|
|
|
22
22
|
it "can process an erb template" do
|
|
23
23
|
data = {repo_code: "ABC", name: "ABC Archive", agent_contact_name: "ABC Admin"}
|
|
24
|
-
|
|
25
|
-
expect(
|
|
24
|
+
record = ArchivesSpace::Template.process("repository_with_agent.json.erb", data)
|
|
25
|
+
expect(record["repository"]["repo_code"]).to eq data[:repo_code]
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
it "can process a jbuilder template" do
|
|
29
29
|
data = {"title" => "Title", "object_number" => "001.001", "description_level" => "collection"}
|
|
30
|
-
|
|
31
|
-
expect(
|
|
30
|
+
record = ArchivesSpace::Template.process("resource.json.jbuilder", data)
|
|
31
|
+
expect(record["id_0"]).to eq data["object_number"]
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
it "rejects a template that does not match by extension" do
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
http_interactions:
|
|
3
|
+
- request:
|
|
4
|
+
method: post
|
|
5
|
+
uri: http://localhost:8089/users/admin/login?password=wrong
|
|
6
|
+
body:
|
|
7
|
+
encoding: UTF-8
|
|
8
|
+
string: ''
|
|
9
|
+
headers:
|
|
10
|
+
Content-Type:
|
|
11
|
+
- application/json
|
|
12
|
+
User-Agent:
|
|
13
|
+
- ArchivesSpaceClient/0.3.0
|
|
14
|
+
Accept-Encoding:
|
|
15
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
|
16
|
+
Accept:
|
|
17
|
+
- "*/*"
|
|
18
|
+
response:
|
|
19
|
+
status:
|
|
20
|
+
code: 403
|
|
21
|
+
message: Forbidden
|
|
22
|
+
headers:
|
|
23
|
+
Cache-Control:
|
|
24
|
+
- private, must-revalidate, max-age=0
|
|
25
|
+
Content-Type:
|
|
26
|
+
- application/json
|
|
27
|
+
X-Content-Type-Options:
|
|
28
|
+
- nosniff
|
|
29
|
+
Content-Length:
|
|
30
|
+
- '24'
|
|
31
|
+
Server:
|
|
32
|
+
- Jetty(9.4.44.v20210927)
|
|
33
|
+
body:
|
|
34
|
+
encoding: UTF-8
|
|
35
|
+
string: '{"error":"Login failed"}'
|
|
36
|
+
recorded_at: Tue, 22 Apr 2026 12:00:00 GMT
|
|
37
|
+
recorded_with: VCR 6.3.1
|
data/spec/spec_helper.rb
CHANGED
|
@@ -6,8 +6,8 @@ require "vcr"
|
|
|
6
6
|
require "webmock/rspec"
|
|
7
7
|
|
|
8
8
|
# GLOBAL VALUES FOR SPECS
|
|
9
|
-
DEFAULT_BASE_URI = "http://localhost:8089"
|
|
10
9
|
CUSTOM_BASE_URI = "https://archives.university.edu/api"
|
|
10
|
+
DEFAULT_BASE_URI = "http://localhost:8089"
|
|
11
11
|
|
|
12
12
|
VCR.configure do |c|
|
|
13
13
|
c.cassette_library_dir = "spec/fixtures/cassettes"
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: archivesspace-client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mark Cooper
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: aruba
|
|
@@ -76,72 +75,72 @@ dependencies:
|
|
|
76
75
|
name: rspec
|
|
77
76
|
requirement: !ruby/object:Gem::Requirement
|
|
78
77
|
requirements:
|
|
79
|
-
- -
|
|
78
|
+
- - "~>"
|
|
80
79
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: 3.
|
|
80
|
+
version: '3.13'
|
|
82
81
|
type: :development
|
|
83
82
|
prerelease: false
|
|
84
83
|
version_requirements: !ruby/object:Gem::Requirement
|
|
85
84
|
requirements:
|
|
86
|
-
- -
|
|
85
|
+
- - "~>"
|
|
87
86
|
- !ruby/object:Gem::Version
|
|
88
|
-
version: 3.
|
|
87
|
+
version: '3.13'
|
|
89
88
|
- !ruby/object:Gem::Dependency
|
|
90
89
|
name: rubocop
|
|
91
90
|
requirement: !ruby/object:Gem::Requirement
|
|
92
91
|
requirements:
|
|
93
|
-
- -
|
|
92
|
+
- - "~>"
|
|
94
93
|
- !ruby/object:Gem::Version
|
|
95
|
-
version: '1.
|
|
94
|
+
version: '1.72'
|
|
96
95
|
type: :development
|
|
97
96
|
prerelease: false
|
|
98
97
|
version_requirements: !ruby/object:Gem::Requirement
|
|
99
98
|
requirements:
|
|
100
|
-
- -
|
|
99
|
+
- - "~>"
|
|
101
100
|
- !ruby/object:Gem::Version
|
|
102
|
-
version: '1.
|
|
101
|
+
version: '1.72'
|
|
103
102
|
- !ruby/object:Gem::Dependency
|
|
104
103
|
name: standard
|
|
105
104
|
requirement: !ruby/object:Gem::Requirement
|
|
106
105
|
requirements:
|
|
107
|
-
- -
|
|
106
|
+
- - "~>"
|
|
108
107
|
- !ruby/object:Gem::Version
|
|
109
|
-
version: 1.
|
|
108
|
+
version: '1.44'
|
|
110
109
|
type: :development
|
|
111
110
|
prerelease: false
|
|
112
111
|
version_requirements: !ruby/object:Gem::Requirement
|
|
113
112
|
requirements:
|
|
114
|
-
- -
|
|
113
|
+
- - "~>"
|
|
115
114
|
- !ruby/object:Gem::Version
|
|
116
|
-
version: 1.
|
|
115
|
+
version: '1.44'
|
|
117
116
|
- !ruby/object:Gem::Dependency
|
|
118
117
|
name: vcr
|
|
119
118
|
requirement: !ruby/object:Gem::Requirement
|
|
120
119
|
requirements:
|
|
121
|
-
- -
|
|
120
|
+
- - "~>"
|
|
122
121
|
- !ruby/object:Gem::Version
|
|
123
|
-
version: 6.
|
|
122
|
+
version: '6.3'
|
|
124
123
|
type: :development
|
|
125
124
|
prerelease: false
|
|
126
125
|
version_requirements: !ruby/object:Gem::Requirement
|
|
127
126
|
requirements:
|
|
128
|
-
- -
|
|
127
|
+
- - "~>"
|
|
129
128
|
- !ruby/object:Gem::Version
|
|
130
|
-
version: 6.
|
|
129
|
+
version: '6.3'
|
|
131
130
|
- !ruby/object:Gem::Dependency
|
|
132
131
|
name: webmock
|
|
133
132
|
requirement: !ruby/object:Gem::Requirement
|
|
134
133
|
requirements:
|
|
135
|
-
- -
|
|
134
|
+
- - "~>"
|
|
136
135
|
- !ruby/object:Gem::Version
|
|
137
|
-
version: 3.
|
|
136
|
+
version: '3.24'
|
|
138
137
|
type: :development
|
|
139
138
|
prerelease: false
|
|
140
139
|
version_requirements: !ruby/object:Gem::Requirement
|
|
141
140
|
requirements:
|
|
142
|
-
- -
|
|
141
|
+
- - "~>"
|
|
143
142
|
- !ruby/object:Gem::Version
|
|
144
|
-
version: 3.
|
|
143
|
+
version: '3.24'
|
|
145
144
|
- !ruby/object:Gem::Dependency
|
|
146
145
|
name: dry-cli
|
|
147
146
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -184,34 +183,20 @@ dependencies:
|
|
|
184
183
|
- - "~>"
|
|
185
184
|
- !ruby/object:Gem::Version
|
|
186
185
|
version: '2.0'
|
|
187
|
-
- !ruby/object:Gem::Dependency
|
|
188
|
-
name: nokogiri
|
|
189
|
-
requirement: !ruby/object:Gem::Requirement
|
|
190
|
-
requirements:
|
|
191
|
-
- - "~>"
|
|
192
|
-
- !ruby/object:Gem::Version
|
|
193
|
-
version: '1.10'
|
|
194
|
-
type: :runtime
|
|
195
|
-
prerelease: false
|
|
196
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
197
|
-
requirements:
|
|
198
|
-
- - "~>"
|
|
199
|
-
- !ruby/object:Gem::Version
|
|
200
|
-
version: '1.10'
|
|
201
186
|
- !ruby/object:Gem::Dependency
|
|
202
187
|
name: jbuilder
|
|
203
188
|
requirement: !ruby/object:Gem::Requirement
|
|
204
189
|
requirements:
|
|
205
190
|
- - "~>"
|
|
206
191
|
- !ruby/object:Gem::Version
|
|
207
|
-
version: 2.
|
|
192
|
+
version: '2.12'
|
|
208
193
|
type: :runtime
|
|
209
194
|
prerelease: false
|
|
210
195
|
version_requirements: !ruby/object:Gem::Requirement
|
|
211
196
|
requirements:
|
|
212
197
|
- - "~>"
|
|
213
198
|
- !ruby/object:Gem::Version
|
|
214
|
-
version: 2.
|
|
199
|
+
version: '2.12'
|
|
215
200
|
description: Interact with ArchivesSpace via the API.
|
|
216
201
|
email:
|
|
217
202
|
- mark.c.cooper@outlook.com
|
|
@@ -237,6 +222,7 @@ files:
|
|
|
237
222
|
- examples/repo_and_user.rb
|
|
238
223
|
- examples/templates.rb
|
|
239
224
|
- examples/test_connection.rb
|
|
225
|
+
- examples/update_feed.rb
|
|
240
226
|
- examples/user_groups.rb
|
|
241
227
|
- exe/asclient
|
|
242
228
|
- features/exec.feature
|
|
@@ -263,12 +249,12 @@ files:
|
|
|
263
249
|
- spec/archivesspace/configuration_spec.rb
|
|
264
250
|
- spec/archivesspace/templates_spec.rb
|
|
265
251
|
- spec/fixtures/cassettes/backend_version.yml
|
|
252
|
+
- spec/fixtures/cassettes/login_failure.yml
|
|
266
253
|
- spec/spec_helper.rb
|
|
267
254
|
homepage: ''
|
|
268
255
|
licenses:
|
|
269
256
|
- MIT
|
|
270
257
|
metadata: {}
|
|
271
|
-
post_install_message:
|
|
272
258
|
rdoc_options: []
|
|
273
259
|
require_paths:
|
|
274
260
|
- lib
|
|
@@ -283,8 +269,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
283
269
|
- !ruby/object:Gem::Version
|
|
284
270
|
version: '0'
|
|
285
271
|
requirements: []
|
|
286
|
-
rubygems_version:
|
|
287
|
-
signing_key:
|
|
272
|
+
rubygems_version: 4.0.10
|
|
288
273
|
specification_version: 4
|
|
289
274
|
summary: Interact with ArchivesSpace via the API.
|
|
290
275
|
test_files: []
|