calmlens 0.21.0 → 0.22.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/README.md +2 -1
- data/lib/calmlens/assets.rb +46 -16
- data/lib/calmlens/error_codes.rb +20 -0
- data/lib/calmlens/errors.rb +9 -0
- data/lib/calmlens/option_keys.rb +10 -1
- data/lib/calmlens/project_configuration.rb +113 -0
- data/lib/calmlens/server_client.rb +9 -0
- data/lib/calmlens/testing/fake_api.rb +281 -42
- data/lib/calmlens/testing/mock_decision.rb +2 -1
- data/lib/calmlens/testing/test_inputs.rb +1 -2
- data/lib/calmlens/testing.rb +20 -3
- data/lib/calmlens/upload_body.rb +85 -2
- data/lib/calmlens/version.rb +1 -1
- data/lib/calmlens.rb +1 -0
- data/sig/calmlens.rbs +25 -0
- data/sig/error_codes.rbs +10 -0
- data/sig/types.rbs +166 -7
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5fd7cb8e811f68c6be7989deb980a259d4a5643bc6f4402324c64236d258661b
|
|
4
|
+
data.tar.gz: f5e03fc720335e9c2ee2116549ddad9407a627449aed230f31eacf9a31743a3d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ea06ee7b551c7e4a4336f3fb972e0e1181a55b5a148cb89c3b281dff789efe60289db280c18ffe700f1e883f763be60b10560b6a8321773c776aa40df2c57c13
|
|
7
|
+
data.tar.gz: b50571100307aaa792130cf4ca1d980232185613d9376a244b7857a7f052e0e43ffcbaa584fa661e869d349c3971e9d5199a07ac053844ee3ddbaa496db5aa81
|
data/README.md
CHANGED
|
@@ -69,6 +69,7 @@ New statuses and fields may appear in later API versions. The SDK returns them u
|
|
|
69
69
|
- [Serve content from the CDN](https://calmlens.com/docs/sdk/ruby#cdn-methods), with [lenses, transforms and signed URLs](https://calmlens.com/docs/sdk/ruby/reference#cdn-urls) and [age-restricted delivery](https://calmlens.com/docs/guides/delivering-assets#age-restricted-assets).
|
|
70
70
|
- [Organise assets in folders](https://calmlens.com/docs/sdk/ruby/reference#folders), [search them](https://calmlens.com/docs/guides/search) and [page through lists](https://calmlens.com/docs/sdk/ruby#pagination).
|
|
71
71
|
- [Match images against hash lists](https://calmlens.com/docs/sdk/ruby/reference#hash-lists).
|
|
72
|
+
- Keep [upload presets](https://calmlens.com/docs/guides/upload-presets), project settings and metadata fields in your code: `upload_presets` (`list`, `each`, `ensure`, `delete`), `project_settings` (`get`, `update`) and `metadata_fields` (`list`, `ensure`, `delete`). `ensure` and `update` create or replace by key or ID, and the `revision` you read refuses a change made since.
|
|
72
73
|
- [Read the events feed](https://calmlens.com/docs/sdk/ruby#pagination) and [verify webhooks in Rails or Rack](https://calmlens.com/docs/sdk/ruby#webhooks).
|
|
73
74
|
- [Handle errors](https://calmlens.com/docs/sdk/ruby/reference#errors) with automatic [retries, timeouts and idempotency keys](https://calmlens.com/docs/sdk/ruby/reference#retries-and-timeouts).
|
|
74
75
|
- [Type-check your code with RBS signatures](https://calmlens.com/docs/sdk/ruby/reference#types).
|
|
@@ -79,7 +80,7 @@ Every method is listed in the [Ruby SDK documentation](https://calmlens.com/docs
|
|
|
79
80
|
|
|
80
81
|
`CalmLens::MockServerClient` from `calmlens/testing` runs the real client against an in-memory stand-in for the API and CDN, so you can test your integration offline. See [Ruby testing](https://calmlens.com/docs/sdk/ruby/testing).
|
|
81
82
|
|
|
82
|
-
`CalmLens::TestInputs` signs test inputs with your project's test input key from the portal: `generate_text_code` turns a scenario, preset or signal into a text code, `paint_image` paints it as a test image, and `generate_media_code` gives a phrase for audio and video, so the real API returns the scenario you declared
|
|
83
|
+
`CalmLens::TestInputs` signs test inputs with your project's test input key from the portal: `generate_text_code` turns a scenario, preset or signal into a text code, `paint_image` paints it as a test image, and `generate_media_code` gives a phrase for audio and video, so the real API returns the scenario you declared. Submit a text code as the whole text and a test image as the whole upload.
|
|
83
84
|
|
|
84
85
|
## Links
|
|
85
86
|
|
data/lib/calmlens/assets.rb
CHANGED
|
@@ -15,8 +15,11 @@ module CalmLens
|
|
|
15
15
|
# The prefix of this resource's operations in Internal::OPTION_KEYS.
|
|
16
16
|
OPERATIONS = 'assets'
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
# The asset fields an upload carries in its body: the JSON body for text, the `options` part of
|
|
19
|
+
# an upload form for files. They never go in the URL, which proxies and servers log, and the
|
|
20
|
+
# API refuses them there.
|
|
21
|
+
UPLOAD_OPTION_KEYS = %w[name description processingOptions visibility metadata tags authorId context externalId
|
|
22
|
+
externalUrl folderId uploadPresetId].freeze
|
|
20
23
|
MAX_MULTIPART_IMAGE_BYTES = 20 * 1024 * 1024
|
|
21
24
|
# The API's limits for one-request uploads: images up to 10 MiB (larger ones are uploaded in
|
|
22
25
|
# parts), audio and video up to 50 MiB and other files up to 5,000 MiB.
|
|
@@ -276,6 +279,11 @@ module CalmLens
|
|
|
276
279
|
# `{type:, data:}` where `data` is a binary String or an IO. An IO streams without being read into
|
|
277
280
|
# memory; pass `size_in_bytes:` when its length is unknown (a pipe or socket).
|
|
278
281
|
#
|
|
282
|
+
# Text is sent as a JSON body. Other content is sent as `multipart/form-data`: the asset's fields
|
|
283
|
+
# (name, description, metadata, author ID, context and so on) in its `options` part, then the
|
|
284
|
+
# file. The URL carries only transport values (`wait`, the content type and sizes), never the
|
|
285
|
+
# asset's fields.
|
|
286
|
+
#
|
|
279
287
|
# The request carries an `Idempotency-Key` (generated unless you pass
|
|
280
288
|
# `request_options: {idempotency_key:}`), so a retried upload never creates a second asset.
|
|
281
289
|
#
|
|
@@ -395,13 +403,37 @@ module CalmLens
|
|
|
395
403
|
return upload_in_parts(options, request_options, wait, mime, body) if !multipart && splits?(content, body)
|
|
396
404
|
|
|
397
405
|
check_upload_size(mime, body.size) unless multipart || @session.defer_upload_checks
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
406
|
+
part_query = first_part_query(options, content, mime, body) if multipart
|
|
407
|
+
if content.key?('plainText')
|
|
408
|
+
return expect_asset(request('POST', project('assets'), query: { 'wait' => wait },
|
|
409
|
+
body: text_body(options, content, multipart),
|
|
410
|
+
idempotent: true, request_options: request_options))
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
query = { 'wait' => wait, 'contentType' => content['type'], 'sizeInBytes' => body.size }
|
|
414
|
+
send_form(query.merge(part_query || {}), upload_fields(options), content['type'], body, multipart, request_options)
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
# The asset fields an upload sends, without unset values.
|
|
418
|
+
def upload_fields(options) = options.slice(*UPLOAD_OPTION_KEYS).compact
|
|
419
|
+
|
|
420
|
+
# The JSON body of a text upload: its fields and `content`, or a first `part` with the sizes.
|
|
421
|
+
def text_body(options, content, multipart)
|
|
422
|
+
text = content.except('sizeInBytes')
|
|
423
|
+
return upload_fields(options).merge('content' => text) unless multipart
|
|
424
|
+
|
|
425
|
+
sizes = { 'sizeInBytes' => options['sizeInBytes'] || content['sizeInBytes'],
|
|
426
|
+
'totalSizeInBytes' => options['totalSizeInBytes'] }.compact
|
|
427
|
+
upload_fields(options).merge('part' => text, **sizes)
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
# Sends file content, or a first part, as an upload form: the fields in its `options` part and
|
|
431
|
+
# the bytes in its `file` part. The query holds only transport values.
|
|
432
|
+
def send_form(query, fields, type, body, multipart, request_options)
|
|
433
|
+
form, form_type = body.to_form(JSON.generate(fields), type)
|
|
401
434
|
expect_asset(request('POST', project('assets'),
|
|
402
|
-
query: query, raw:
|
|
403
|
-
|
|
404
|
-
headers: { 'Content-Type' => content['type'], 'X-CalmLens-Upload' => multipart ? 'part' : 'content' }))
|
|
435
|
+
query: query, raw: form, idempotent: true, request_options: request_options, upload: true,
|
|
436
|
+
headers: { 'Content-Type' => form_type, 'X-CalmLens-Upload' => multipart ? 'part' : 'content' }))
|
|
405
437
|
end
|
|
406
438
|
|
|
407
439
|
# Whether content goes in parts: not text, of known size, readable again and larger than a part.
|
|
@@ -428,12 +460,9 @@ module CalmLens
|
|
|
428
460
|
piece = ->(number) { body.slice((number - 1) * part_size, [part_size, total - ((number - 1) * part_size)].min) }
|
|
429
461
|
first = piece.call(1)
|
|
430
462
|
type = options.dig('content', 'type')
|
|
431
|
-
query =
|
|
432
|
-
|
|
433
|
-
asset =
|
|
434
|
-
query: query, raw: first, idempotent: true, upload: true,
|
|
435
|
-
request_options: request_options.merge(idempotency_key: key),
|
|
436
|
-
headers: { 'Content-Type' => type, 'X-CalmLens-Upload' => 'part' }))
|
|
463
|
+
query = { 'wait' => wait, 'contentType' => type, 'sizeInBytes' => first.size, 'partNumber' => 1, 'isFinal' => false,
|
|
464
|
+
'totalSizeInBytes' => total }
|
|
465
|
+
asset = send_form(query, upload_fields(options), type, first, true, request_options.merge(idempotency_key: key))
|
|
437
466
|
send_remaining_parts(asset, count, piece, key, request_options)
|
|
438
467
|
end
|
|
439
468
|
|
|
@@ -473,7 +502,7 @@ module CalmLens
|
|
|
473
502
|
headers: headers))
|
|
474
503
|
end
|
|
475
504
|
|
|
476
|
-
# Keeps only the earlier posts CalmLens uses, which keeps
|
|
505
|
+
# Keeps only the earlier posts CalmLens uses, which keeps an upload's body short.
|
|
477
506
|
def with_used_context(options)
|
|
478
507
|
return options unless options.key?('context')
|
|
479
508
|
|
|
@@ -483,7 +512,8 @@ module CalmLens
|
|
|
483
512
|
options.merge('context' => { 'items' => ModerationContext.select_items(context['items']) })
|
|
484
513
|
end
|
|
485
514
|
|
|
486
|
-
# The
|
|
515
|
+
# The transport values of a first multipart part: its number, whether it is the last and the
|
|
516
|
+
# declared total.
|
|
487
517
|
def first_part_query(options, content, mime, body)
|
|
488
518
|
total = options['totalSizeInBytes']
|
|
489
519
|
unless total.nil? || (total.is_a?(Integer) && total.positive?)
|
data/lib/calmlens/error_codes.rb
CHANGED
|
@@ -40,12 +40,14 @@ module CalmLens
|
|
|
40
40
|
PERMISSION_DENIED = 'auth/permission-denied'
|
|
41
41
|
UPLOAD_TOO_LARGE = 'upload/too-large'
|
|
42
42
|
DOCUMENT_TOO_MANY_ITEMS = 'document/too-many-items'
|
|
43
|
+
MEDIA_DURATION_LIMIT = 'media/duration-limit'
|
|
43
44
|
INVALID_IMAGE = 'image/invalid'
|
|
44
45
|
IMAGE_TOO_LARGE = 'image/too-large'
|
|
45
46
|
FREE_UPLOADS_EXHAUSTED = 'usage/free-uploads-exhausted'
|
|
46
47
|
UPLOADS_PAUSED = 'usage/uploads-paused'
|
|
47
48
|
UNSUPPORTED_UPLOAD_TYPE = 'upload/unsupported-type'
|
|
48
49
|
INVALID_UPLOAD_PAYLOAD = 'upload-payload/invalid'
|
|
50
|
+
UPLOAD_OPTIONS_IN_QUERY = 'upload/options-in-query'
|
|
49
51
|
USE_UPLOAD_PART = 'upload/use-upload-part'
|
|
50
52
|
UPLOAD_NOT_OPEN = 'upload/not-open'
|
|
51
53
|
INVALID_UPLOAD_PART_NUMBER = 'upload-part/invalid-number'
|
|
@@ -102,6 +104,14 @@ module CalmLens
|
|
|
102
104
|
UPLOAD_PRESET_DAILY_LIMIT_REACHED = 'upload-preset/daily-limit-reached'
|
|
103
105
|
UPLOAD_PRESET_ORIGIN_NOT_ALLOWED = 'upload-preset/origin-not-allowed'
|
|
104
106
|
UPLOAD_PRESET_FIELD_NOT_ALLOWED = 'upload-preset/field-not-allowed'
|
|
107
|
+
UPLOAD_PRESET_REVISION_CONFLICT = 'upload-preset/revision-conflict'
|
|
108
|
+
UPLOAD_PRESET_KEY_TAKEN = 'upload-preset/key-taken'
|
|
109
|
+
UPLOAD_PRESET_DAILY_LIMIT_REQUIRED = 'upload-preset/daily-limit-required'
|
|
110
|
+
UPLOAD_PRESET_INVALID_FOLDER = 'upload-preset/invalid-folder'
|
|
111
|
+
UPLOAD_PRESET_INVALID_POLICY = 'upload-preset/invalid-policy'
|
|
112
|
+
PROJECT_SETTINGS_REVISION_CONFLICT = 'project-settings/revision-conflict'
|
|
113
|
+
SEARCH_ESTIMATE_CHANGED = 'search/estimate-changed'
|
|
114
|
+
METADATA_FIELD_NOT_FOUND = 'metadata-field/not-found'
|
|
105
115
|
UPLOAD_TOKEN_INVALID = 'upload-token/invalid'
|
|
106
116
|
UPLOAD_TOKEN_EXPIRED = 'upload-token/expired'
|
|
107
117
|
UPLOAD_TOKEN_USED = 'upload-token/used'
|
|
@@ -153,12 +163,14 @@ module CalmLens
|
|
|
153
163
|
'auth/permission-denied' => 403,
|
|
154
164
|
'upload/too-large' => 413,
|
|
155
165
|
'document/too-many-items' => 422,
|
|
166
|
+
'media/duration-limit' => 422,
|
|
156
167
|
'image/invalid' => 422,
|
|
157
168
|
'image/too-large' => 422,
|
|
158
169
|
'usage/free-uploads-exhausted' => 403,
|
|
159
170
|
'usage/uploads-paused' => 402,
|
|
160
171
|
'upload/unsupported-type' => 415,
|
|
161
172
|
'upload-payload/invalid' => 400,
|
|
173
|
+
'upload/options-in-query' => 400,
|
|
162
174
|
'upload/use-upload-part' => 409,
|
|
163
175
|
'upload/not-open' => 409,
|
|
164
176
|
'upload-part/invalid-number' => 409,
|
|
@@ -215,6 +227,14 @@ module CalmLens
|
|
|
215
227
|
'upload-preset/daily-limit-reached' => 429,
|
|
216
228
|
'upload-preset/origin-not-allowed' => 403,
|
|
217
229
|
'upload-preset/field-not-allowed' => 400,
|
|
230
|
+
'upload-preset/revision-conflict' => 409,
|
|
231
|
+
'upload-preset/key-taken' => 409,
|
|
232
|
+
'upload-preset/daily-limit-required' => 400,
|
|
233
|
+
'upload-preset/invalid-folder' => 400,
|
|
234
|
+
'upload-preset/invalid-policy' => 400,
|
|
235
|
+
'project-settings/revision-conflict' => 409,
|
|
236
|
+
'search/estimate-changed' => 409,
|
|
237
|
+
'metadata-field/not-found' => 404,
|
|
218
238
|
'upload-token/invalid' => 401,
|
|
219
239
|
'upload-token/expired' => 401,
|
|
220
240
|
'upload-token/used' => 409,
|
data/lib/calmlens/errors.rb
CHANGED
|
@@ -61,6 +61,15 @@ module CalmLens
|
|
|
61
61
|
Error.parse_retry_after(headers['retry-after'])
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
+
# @return [Boolean] true when the SDK raised this error itself, with no HTTP response: before
|
|
65
|
+
# sending (an invalid argument or option, or content it checks first, such as
|
|
66
|
+
# `upload/unsupported-type`), or because no response arrived (a timeout or a connection
|
|
67
|
+
# failure). The code is the one the API would use; `status` and `request_id` are nil, so
|
|
68
|
+
# branch on `code`.
|
|
69
|
+
def local?
|
|
70
|
+
status.nil?
|
|
71
|
+
end
|
|
72
|
+
|
|
64
73
|
# @return [Boolean] true when the resource does not exist.
|
|
65
74
|
def not_found?
|
|
66
75
|
status == 404 || code.end_with?('/not-found')
|
data/lib/calmlens/option_keys.rb
CHANGED
|
@@ -62,6 +62,9 @@ module CalmLens
|
|
|
62
62
|
'lenses.list' => %w[cursor pageSize sort].freeze,
|
|
63
63
|
'lenses.retrieve' => %w[lensId].freeze,
|
|
64
64
|
'lenses.update' => %w[active description lensId name transform type].freeze,
|
|
65
|
+
'metadataFields.delete' => %w[fieldId revision].freeze,
|
|
66
|
+
'metadataFields.ensure' => %w[fields revision].freeze,
|
|
67
|
+
'metadataFields.list' => %w[].freeze,
|
|
65
68
|
'policies.assign' => %w[policyId].freeze,
|
|
66
69
|
'policies.create' => %w[description name presetId settings].freeze,
|
|
67
70
|
'policies.delete' => %w[policyId].freeze,
|
|
@@ -73,10 +76,16 @@ module CalmLens
|
|
|
73
76
|
'policies.setAutomaticUpdates' => %w[enabled policyId presetVersion revision].freeze,
|
|
74
77
|
'policies.update' => %w[description name policyId revision settings].freeze,
|
|
75
78
|
'policies.upgrade' => %w[policyId presetVersion revision].freeze,
|
|
79
|
+
'projectSettings.get' => %w[].freeze,
|
|
80
|
+
'projectSettings.update' => %w[revision searchIndexingBudgetUnits settings].freeze,
|
|
76
81
|
'text.classify' => %w[
|
|
77
82
|
authorId context description externalId externalUrl folderId metadata name processingOptions tags text
|
|
78
83
|
uploadPresetId visibility
|
|
79
|
-
].freeze
|
|
84
|
+
].freeze,
|
|
85
|
+
'uploadPresets.delete' => %w[uploadPresetId].freeze,
|
|
86
|
+
'uploadPresets.each' => %w[cursor pageSize sort].freeze,
|
|
87
|
+
'uploadPresets.ensure' => %w[uploadPresets].freeze,
|
|
88
|
+
'uploadPresets.list' => %w[cursor pageSize sort].freeze
|
|
80
89
|
}.freeze
|
|
81
90
|
|
|
82
91
|
# The option keys each method sends as null when given nil; any other option given as nil
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CalmLens
|
|
4
|
+
# The project's upload presets: the rules for uploads made from browsers and apps. {#ensure}
|
|
5
|
+
# creates or replaces presets by `key`, for applications that declare theirs in code or
|
|
6
|
+
# configuration. Reach it through {ServerClient#upload_presets}.
|
|
7
|
+
class UploadPresets < Resource
|
|
8
|
+
# The prefix of this resource's operations in Internal::OPTION_KEYS.
|
|
9
|
+
OPERATIONS = 'uploadPresets'
|
|
10
|
+
|
|
11
|
+
# Lists one page of the project's upload presets, oldest first unless `sort` says otherwise.
|
|
12
|
+
# @option options [String] :cursor the previous page's `nextCursor`
|
|
13
|
+
# @option options [Integer] :page_size 1 to 100, default 50
|
|
14
|
+
# @option options [String] :sort `createdAt` and `id`, comma-separated, descending when prefixed
|
|
15
|
+
# with `-`; `createdAt` by default
|
|
16
|
+
# @return [Hash] a cursor page: items, nextCursor and hasMore.
|
|
17
|
+
def list(options = {})
|
|
18
|
+
call(options, __method__) do |api, request|
|
|
19
|
+
cursor_page(request('GET', project('upload-presets'), query: api, request_options: request), 'upload preset')
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Iterates every upload preset of the project, fetching pages as needed.
|
|
24
|
+
# @param options [Hash] the options of {#list}; `cursor` sets the starting position.
|
|
25
|
+
# @yieldparam upload_preset [Hash]
|
|
26
|
+
# @return [Enumerator, nil] an Enumerator when no block is given.
|
|
27
|
+
def each(options = {}, &block)
|
|
28
|
+
return enum_for(:each, options) unless block
|
|
29
|
+
|
|
30
|
+
each_item(options, __method__, method(:list), &block)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Creates each preset, or replaces it with the definition sent, by `key`. Fields left out take
|
|
34
|
+
# their defaults; an unchanged preset keeps its revision. Every preset is checked before any is
|
|
35
|
+
# saved. Send each preset's `revision` (0 for one that must not exist yet) to refuse a change
|
|
36
|
+
# made since with `upload-preset/revision-conflict`.
|
|
37
|
+
# @option options [Array<Hash>] :upload_presets `[{key:, name:, revision:, access:, enabled:, ...}]`,
|
|
38
|
+
# at most 50
|
|
39
|
+
# @return [Hash] `uploadPresets`: the stored presets, in the order sent.
|
|
40
|
+
def ensure(options)
|
|
41
|
+
call(options, __method__) do |api, request|
|
|
42
|
+
request('PUT', project('upload-presets'), body: api, request_options: request)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Deletes an upload preset. Browsers can no longer upload through it; assets already uploaded stay.
|
|
47
|
+
# @option options [String] :upload_preset_id
|
|
48
|
+
# @return [nil]
|
|
49
|
+
def delete(options)
|
|
50
|
+
call(options, __method__) do |api, request|
|
|
51
|
+
request('DELETE', "/upload-presets/#{Internal.segment(api['uploadPresetId'])}", request_options: request)
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# The project's settings, with defaults filled in. {#update} replaces them: settings left out
|
|
58
|
+
# return to their defaults. Send the `revision` you read to refuse a change made since with
|
|
59
|
+
# `project-settings/revision-conflict`. Reach it through {ServerClient#project_settings}.
|
|
60
|
+
class ProjectSettings < Resource
|
|
61
|
+
# The prefix of this resource's operations in Internal::OPTION_KEYS.
|
|
62
|
+
OPERATIONS = 'projectSettings'
|
|
63
|
+
|
|
64
|
+
# @return [Hash] `projectId`, `revision` and `settings`.
|
|
65
|
+
def get(options = {})
|
|
66
|
+
call(options, __method__) { |_api, request| request('GET', project('settings'), request_options: request) }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Replaces the project's settings; unchanged settings keep their revision. The project's policy
|
|
70
|
+
# and metadata fields have their own methods.
|
|
71
|
+
# @option options [Integer] :revision the revision you read
|
|
72
|
+
# @option options [Hash] :settings the complete settings
|
|
73
|
+
# @option options [Numeric] :search_indexing_budget_units needed when turning on
|
|
74
|
+
# `aiMediaSearchEnabled`: the most indexing units you accept for existing media
|
|
75
|
+
# @return [Hash] `projectId`, `revision` and `settings`.
|
|
76
|
+
def update(options)
|
|
77
|
+
call(options, __method__) { |api, request| request('PUT', project('settings'), body: api, request_options: request) }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# The project's metadata fields, in display order. They share the project settings' `revision`;
|
|
82
|
+
# {#ensure} creates or replaces fields by ID and keeps the others. Reach it through
|
|
83
|
+
# {ServerClient#metadata_fields}.
|
|
84
|
+
class MetadataFields < Resource
|
|
85
|
+
# The prefix of this resource's operations in Internal::OPTION_KEYS.
|
|
86
|
+
OPERATIONS = 'metadataFields'
|
|
87
|
+
|
|
88
|
+
# @return [Hash] `projectId`, `revision` and `fields`.
|
|
89
|
+
def list(options = {})
|
|
90
|
+
call(options, __method__) { |_api, request| request('GET', project('metadata-fields'), request_options: request) }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Creates each field, or replaces it by ID. Other fields are kept; new ones are added at the end.
|
|
94
|
+
# @option options [Integer] :revision the revision you read
|
|
95
|
+
# @option options [Array<Hash>] :fields `[{id:, title:, type:, icon:, color:, description:}]`
|
|
96
|
+
# @return [Hash] `projectId`, `revision` and `fields`.
|
|
97
|
+
def ensure(options)
|
|
98
|
+
call(options, __method__) { |api, request| request('PUT', project('metadata-fields'), body: api, request_options: request) }
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Deletes a field definition; assets keep the metadata values they hold.
|
|
102
|
+
# @option options [String] :field_id
|
|
103
|
+
# @option options [Integer] :revision the revision you read
|
|
104
|
+
# @return [nil]
|
|
105
|
+
def delete(options)
|
|
106
|
+
call(options, __method__) do |api, request|
|
|
107
|
+
request('DELETE', project("metadata-fields/#{Internal.segment(api['fieldId'])}"),
|
|
108
|
+
query: without(api, 'fieldId'), request_options: request)
|
|
109
|
+
nil
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -51,6 +51,12 @@ module CalmLens
|
|
|
51
51
|
attr_reader :cdn
|
|
52
52
|
# @return [Lenses]
|
|
53
53
|
attr_reader :lenses
|
|
54
|
+
# @return [UploadPresets]
|
|
55
|
+
attr_reader :upload_presets
|
|
56
|
+
# @return [ProjectSettings]
|
|
57
|
+
attr_reader :project_settings
|
|
58
|
+
# @return [MetadataFields]
|
|
59
|
+
attr_reader :metadata_fields
|
|
54
60
|
|
|
55
61
|
# @param api_key [String] a project API key. Keep it on your server.
|
|
56
62
|
# @param project_id [String]
|
|
@@ -100,6 +106,9 @@ module CalmLens
|
|
|
100
106
|
@events = Events.new(@session)
|
|
101
107
|
@cdn = CDN.new(@session)
|
|
102
108
|
@lenses = Lenses.new(@session)
|
|
109
|
+
@upload_presets = UploadPresets.new(@session)
|
|
110
|
+
@project_settings = ProjectSettings.new(@session)
|
|
111
|
+
@metadata_fields = MetadataFields.new(@session)
|
|
103
112
|
end
|
|
104
113
|
|
|
105
114
|
# @return [String]
|