resourcespace-ruby 0.1.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 +7 -0
- data/.rspec +1 -0
- data/.rubocop.yml +8 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +22 -0
- data/LICENSE.txt +21 -0
- data/README.md +355 -0
- data/Rakefile +6 -0
- data/lib/resourcespace/client.rb +245 -0
- data/lib/resourcespace/collection.rb +211 -0
- data/lib/resourcespace/configuration.rb +127 -0
- data/lib/resourcespace/errors.rb +111 -0
- data/lib/resourcespace/metadata.rb +298 -0
- data/lib/resourcespace/resource.rb +285 -0
- data/lib/resourcespace/search.rb +259 -0
- data/lib/resourcespace/user.rb +188 -0
- data/lib/resourcespace/version.rb +6 -0
- data/lib/resourcespace.rb +71 -0
- data/resourcespace-ruby.gemspec +49 -0
- metadata +247 -0
@@ -0,0 +1,211 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ResourceSpace
|
4
|
+
# Collection management interface for ResourceSpace API
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# collections = client.collections
|
8
|
+
#
|
9
|
+
# # Get user collections
|
10
|
+
# user_collections = collections.get_user_collections
|
11
|
+
#
|
12
|
+
# # Create a new collection
|
13
|
+
# collection = collections.create_collection("My Web Assets")
|
14
|
+
#
|
15
|
+
# # Add resources to collection
|
16
|
+
# collections.add_resource_to_collection(123, collection_id)
|
17
|
+
class Collection
|
18
|
+
# @return [Client] the ResourceSpace client
|
19
|
+
attr_reader :client
|
20
|
+
|
21
|
+
# Initialize the collection interface
|
22
|
+
#
|
23
|
+
# @param client [Client] ResourceSpace client instance
|
24
|
+
def initialize(client)
|
25
|
+
@client = client
|
26
|
+
end
|
27
|
+
|
28
|
+
# Get user collections
|
29
|
+
#
|
30
|
+
# @param user [String] username (optional, defaults to current user)
|
31
|
+
# @return [Array] user collections
|
32
|
+
def get_user_collections(user = nil)
|
33
|
+
params = {}
|
34
|
+
params[:param1] = user if user
|
35
|
+
|
36
|
+
client.get("get_user_collections", params)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Create a new collection
|
40
|
+
#
|
41
|
+
# @param name [String] collection name
|
42
|
+
# @param public [Boolean] whether collection is public
|
43
|
+
# @param allow_changes [Boolean] whether to allow changes to collection
|
44
|
+
# @return [Hash] created collection data
|
45
|
+
def create_collection(name, public: false, allow_changes: true)
|
46
|
+
params = {
|
47
|
+
param1: name,
|
48
|
+
param2: public ? "1" : "0"
|
49
|
+
}
|
50
|
+
params[:param3] = allow_changes ? "1" : "0"
|
51
|
+
|
52
|
+
client.post("create_collection", params)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Delete a collection
|
56
|
+
#
|
57
|
+
# @param collection_id [Integer] collection ID
|
58
|
+
# @return [Hash] response
|
59
|
+
def delete_collection(collection_id)
|
60
|
+
client.post("delete_collection", { param1: collection_id.to_s })
|
61
|
+
end
|
62
|
+
|
63
|
+
# Get collection details
|
64
|
+
#
|
65
|
+
# @param collection_id [Integer] collection ID
|
66
|
+
# @return [Hash] collection details
|
67
|
+
def get_collection(collection_id)
|
68
|
+
client.get("get_collection", { param1: collection_id.to_s })
|
69
|
+
end
|
70
|
+
|
71
|
+
# Save collection (update collection details)
|
72
|
+
#
|
73
|
+
# @param collection_id [Integer] collection ID
|
74
|
+
# @param name [String] new collection name
|
75
|
+
# @param public [Boolean] whether collection is public
|
76
|
+
# @param allow_changes [Boolean] whether to allow changes
|
77
|
+
# @return [Hash] response
|
78
|
+
def save_collection(collection_id, name: nil, public: nil, allow_changes: nil)
|
79
|
+
params = { param1: collection_id.to_s }
|
80
|
+
params[:param2] = name if name
|
81
|
+
params[:param3] = public ? "1" : "0" unless public.nil?
|
82
|
+
params[:param4] = allow_changes ? "1" : "0" unless allow_changes.nil?
|
83
|
+
|
84
|
+
client.post("save_collection", params)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Add a resource to a collection
|
88
|
+
#
|
89
|
+
# @param resource_id [Integer] resource ID
|
90
|
+
# @param collection_id [Integer] collection ID
|
91
|
+
# @return [Hash] response
|
92
|
+
def add_resource_to_collection(resource_id, collection_id)
|
93
|
+
client.post("add_resource_to_collection", {
|
94
|
+
param1: resource_id.to_s,
|
95
|
+
param2: collection_id.to_s
|
96
|
+
})
|
97
|
+
end
|
98
|
+
|
99
|
+
# Remove a resource from a collection
|
100
|
+
#
|
101
|
+
# @param resource_id [Integer] resource ID
|
102
|
+
# @param collection_id [Integer] collection ID
|
103
|
+
# @return [Hash] response
|
104
|
+
def remove_resource_from_collection(resource_id, collection_id)
|
105
|
+
client.post("remove_resource_from_collection", {
|
106
|
+
param1: resource_id.to_s,
|
107
|
+
param2: collection_id.to_s
|
108
|
+
})
|
109
|
+
end
|
110
|
+
|
111
|
+
# Show or hide a collection
|
112
|
+
#
|
113
|
+
# @param collection_id [Integer] collection ID
|
114
|
+
# @param show [Boolean] true to show, false to hide
|
115
|
+
# @return [Hash] response
|
116
|
+
def show_hide_collection(collection_id, show: true)
|
117
|
+
client.post("show_hide_collection", {
|
118
|
+
param1: collection_id.to_s,
|
119
|
+
param2: show ? "1" : "0"
|
120
|
+
})
|
121
|
+
end
|
122
|
+
|
123
|
+
# Send collection to admin
|
124
|
+
#
|
125
|
+
# @param collection_id [Integer] collection ID
|
126
|
+
# @param message [String] message to admin
|
127
|
+
# @return [Hash] response
|
128
|
+
def send_collection_to_admin(collection_id, message = "")
|
129
|
+
client.post("send_collection_to_admin", {
|
130
|
+
param1: collection_id.to_s,
|
131
|
+
param2: message
|
132
|
+
})
|
133
|
+
end
|
134
|
+
|
135
|
+
# Search public collections
|
136
|
+
#
|
137
|
+
# @param search_term [String] search term
|
138
|
+
# @return [Array] matching public collections
|
139
|
+
def search_public_collections(search_term)
|
140
|
+
client.get("search_public_collections", { param1: search_term })
|
141
|
+
end
|
142
|
+
|
143
|
+
# Get featured collections
|
144
|
+
#
|
145
|
+
# @return [Array] featured collections
|
146
|
+
def get_featured_collections
|
147
|
+
client.get("get_featured_collections")
|
148
|
+
end
|
149
|
+
|
150
|
+
# Delete all resources in a collection
|
151
|
+
#
|
152
|
+
# @param collection_id [Integer] collection ID
|
153
|
+
# @return [Hash] response
|
154
|
+
def delete_resources_in_collection(collection_id)
|
155
|
+
client.post("delete_resources_in_collection", { param1: collection_id.to_s })
|
156
|
+
end
|
157
|
+
|
158
|
+
# Add multiple resources to a collection
|
159
|
+
#
|
160
|
+
# @param resource_ids [Array<Integer>] array of resource IDs
|
161
|
+
# @param collection_id [Integer] collection ID
|
162
|
+
# @return [Array] array of responses
|
163
|
+
def add_resources_to_collection(resource_ids, collection_id)
|
164
|
+
Array(resource_ids).map do |resource_id|
|
165
|
+
add_resource_to_collection(resource_id, collection_id)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Remove multiple resources from a collection
|
170
|
+
#
|
171
|
+
# @param resource_ids [Array<Integer>] array of resource IDs
|
172
|
+
# @param collection_id [Integer] collection ID
|
173
|
+
# @return [Array] array of responses
|
174
|
+
def remove_resources_from_collection(resource_ids, collection_id)
|
175
|
+
Array(resource_ids).map do |resource_id|
|
176
|
+
remove_resource_from_collection(resource_id, collection_id)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Create a collection for web assets
|
181
|
+
#
|
182
|
+
# @param name [String] collection name
|
183
|
+
# @param asset_type [String] type of web assets ("images", "css", "js", "fonts", "icons")
|
184
|
+
# @param public [Boolean] whether collection is public
|
185
|
+
# @return [Hash] created collection data
|
186
|
+
def create_web_asset_collection(name, asset_type: nil, public: false)
|
187
|
+
collection_name = asset_type ? "#{name} - #{asset_type.capitalize}" : name
|
188
|
+
create_collection(collection_name, public: public)
|
189
|
+
end
|
190
|
+
|
191
|
+
# Get collections containing web assets
|
192
|
+
#
|
193
|
+
# @param asset_type [String] type of web assets to filter by
|
194
|
+
# @return [Array] collections with web assets
|
195
|
+
def get_web_asset_collections(asset_type: nil)
|
196
|
+
collections = get_user_collections
|
197
|
+
|
198
|
+
# Filter collections that likely contain web assets based on name
|
199
|
+
web_asset_keywords = %w[web asset css js javascript image icon font stylesheet]
|
200
|
+
|
201
|
+
if asset_type
|
202
|
+
web_asset_keywords << asset_type.downcase
|
203
|
+
end
|
204
|
+
|
205
|
+
collections.select do |collection|
|
206
|
+
name = collection["name"]&.downcase || ""
|
207
|
+
web_asset_keywords.any? { |keyword| name.include?(keyword) }
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ResourceSpace
|
4
|
+
# Configuration class for ResourceSpace client
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# config = ResourceSpace::Configuration.new
|
8
|
+
# config.url = "https://your-resourcespace.com/api/"
|
9
|
+
# config.user = "your_username"
|
10
|
+
# config.private_key = "your_private_key"
|
11
|
+
class Configuration
|
12
|
+
# @return [String] the ResourceSpace API URL (must end with /api/)
|
13
|
+
attr_accessor :url
|
14
|
+
|
15
|
+
# @return [String] the ResourceSpace username
|
16
|
+
attr_accessor :user
|
17
|
+
|
18
|
+
# @return [String] the private API key for the user
|
19
|
+
attr_accessor :private_key
|
20
|
+
|
21
|
+
# @return [Integer] request timeout in seconds (default: 30)
|
22
|
+
attr_accessor :timeout
|
23
|
+
|
24
|
+
# @return [Integer] number of retry attempts for failed requests (default: 3)
|
25
|
+
attr_accessor :retries
|
26
|
+
|
27
|
+
# @return [String] user agent string for requests
|
28
|
+
attr_accessor :user_agent
|
29
|
+
|
30
|
+
# @return [Boolean] whether to verify SSL certificates (default: true)
|
31
|
+
attr_accessor :verify_ssl
|
32
|
+
|
33
|
+
# @return [String] authentication mode ('userkey', 'sessionkey', or 'native')
|
34
|
+
attr_accessor :auth_mode
|
35
|
+
|
36
|
+
# @return [Hash] default headers to include with all requests
|
37
|
+
attr_accessor :default_headers
|
38
|
+
|
39
|
+
# @return [Boolean] whether to log API requests and responses (default: false)
|
40
|
+
attr_accessor :debug
|
41
|
+
|
42
|
+
# @return [Logger] logger instance for debugging
|
43
|
+
attr_accessor :logger
|
44
|
+
|
45
|
+
# Initialize a new configuration with default values
|
46
|
+
def initialize
|
47
|
+
@url = nil
|
48
|
+
@user = nil
|
49
|
+
@private_key = nil
|
50
|
+
@timeout = 30
|
51
|
+
@retries = 3
|
52
|
+
@user_agent = "ResourceSpace Ruby Client #{ResourceSpace::VERSION}"
|
53
|
+
@verify_ssl = true
|
54
|
+
@auth_mode = "userkey"
|
55
|
+
@default_headers = {}
|
56
|
+
@debug = false
|
57
|
+
@logger = nil
|
58
|
+
end
|
59
|
+
|
60
|
+
# Validate the configuration
|
61
|
+
#
|
62
|
+
# @raise [ConfigurationError] if configuration is invalid
|
63
|
+
# @return [Boolean] true if configuration is valid
|
64
|
+
def validate!
|
65
|
+
errors = []
|
66
|
+
|
67
|
+
errors << "URL is required" if url.nil? || url.empty?
|
68
|
+
errors << "URL must end with /api/" if url && !url.end_with?("/api/")
|
69
|
+
errors << "User is required" if user.nil? || user.empty?
|
70
|
+
errors << "Private key is required" if private_key.nil? || private_key.empty?
|
71
|
+
errors << "Timeout must be positive" if timeout && timeout <= 0
|
72
|
+
errors << "Retries must be non-negative" if retries && retries < 0
|
73
|
+
errors << "Auth mode must be userkey, sessionkey, or native" unless %w[userkey sessionkey native].include?(auth_mode)
|
74
|
+
|
75
|
+
raise ConfigurationError, "Configuration errors: #{errors.join(', ')}" unless errors.empty?
|
76
|
+
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
# Check if configuration is valid without raising an error
|
81
|
+
#
|
82
|
+
# @return [Boolean] true if configuration is valid
|
83
|
+
def valid?
|
84
|
+
validate!
|
85
|
+
true
|
86
|
+
rescue ConfigurationError
|
87
|
+
false
|
88
|
+
end
|
89
|
+
|
90
|
+
# Convert configuration to a hash
|
91
|
+
#
|
92
|
+
# @return [Hash] configuration as a hash
|
93
|
+
def to_h
|
94
|
+
{
|
95
|
+
url: url,
|
96
|
+
user: user,
|
97
|
+
private_key: private_key ? "[REDACTED]" : nil,
|
98
|
+
timeout: timeout,
|
99
|
+
retries: retries,
|
100
|
+
user_agent: user_agent,
|
101
|
+
verify_ssl: verify_ssl,
|
102
|
+
auth_mode: auth_mode,
|
103
|
+
default_headers: default_headers,
|
104
|
+
debug: debug
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
# Create a duplicate of this configuration
|
109
|
+
#
|
110
|
+
# @return [Configuration] a new configuration with the same values
|
111
|
+
def dup
|
112
|
+
new_config = Configuration.new
|
113
|
+
new_config.url = url
|
114
|
+
new_config.user = user
|
115
|
+
new_config.private_key = private_key
|
116
|
+
new_config.timeout = timeout
|
117
|
+
new_config.retries = retries
|
118
|
+
new_config.user_agent = user_agent
|
119
|
+
new_config.verify_ssl = verify_ssl
|
120
|
+
new_config.auth_mode = auth_mode
|
121
|
+
new_config.default_headers = default_headers.dup
|
122
|
+
new_config.debug = debug
|
123
|
+
new_config.logger = logger
|
124
|
+
new_config
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ResourceSpace
|
4
|
+
# Base error class for all ResourceSpace errors
|
5
|
+
class Error < StandardError
|
6
|
+
# @return [Hash, nil] additional error data
|
7
|
+
attr_reader :data
|
8
|
+
|
9
|
+
# @return [Integer, nil] HTTP status code if applicable
|
10
|
+
attr_reader :status_code
|
11
|
+
|
12
|
+
# @return [String, nil] response body if applicable
|
13
|
+
attr_reader :response_body
|
14
|
+
|
15
|
+
# Initialize a new error
|
16
|
+
#
|
17
|
+
# @param message [String] error message
|
18
|
+
# @param data [Hash] additional error data
|
19
|
+
# @param status_code [Integer] HTTP status code
|
20
|
+
# @param response_body [String] HTTP response body
|
21
|
+
def initialize(message = nil, data: nil, status_code: nil, response_body: nil)
|
22
|
+
@data = data
|
23
|
+
@status_code = status_code
|
24
|
+
@response_body = response_body
|
25
|
+
super(message)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Convert error to a hash representation
|
29
|
+
#
|
30
|
+
# @return [Hash] error as a hash
|
31
|
+
def to_h
|
32
|
+
{
|
33
|
+
error: self.class.name,
|
34
|
+
message: message,
|
35
|
+
status_code: status_code,
|
36
|
+
data: data
|
37
|
+
}.compact
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Configuration validation error
|
42
|
+
class ConfigurationError < Error; end
|
43
|
+
|
44
|
+
# Authentication error
|
45
|
+
class AuthenticationError < Error; end
|
46
|
+
|
47
|
+
# Authorization error (user doesn't have permission)
|
48
|
+
class AuthorizationError < Error; end
|
49
|
+
|
50
|
+
# Resource not found error
|
51
|
+
class NotFoundError < Error; end
|
52
|
+
|
53
|
+
# Validation error (invalid parameters)
|
54
|
+
class ValidationError < Error; end
|
55
|
+
|
56
|
+
# Rate limiting error
|
57
|
+
class RateLimitError < Error; end
|
58
|
+
|
59
|
+
# Server error (5xx responses)
|
60
|
+
class ServerError < Error; end
|
61
|
+
|
62
|
+
# Network/connection error
|
63
|
+
class NetworkError < Error; end
|
64
|
+
|
65
|
+
# Request timeout error
|
66
|
+
class TimeoutError < Error; end
|
67
|
+
|
68
|
+
# File upload error
|
69
|
+
class UploadError < Error; end
|
70
|
+
|
71
|
+
# API response parsing error
|
72
|
+
class ParseError < Error; end
|
73
|
+
|
74
|
+
# Resource already exists error
|
75
|
+
class ConflictError < Error; end
|
76
|
+
|
77
|
+
# API quota exceeded error
|
78
|
+
class QuotaExceededError < Error; end
|
79
|
+
|
80
|
+
# Generic client error (4xx responses)
|
81
|
+
class ClientError < Error; end
|
82
|
+
|
83
|
+
# Method to create appropriate error based on HTTP status code
|
84
|
+
#
|
85
|
+
# @param status_code [Integer] HTTP status code
|
86
|
+
# @param message [String] error message
|
87
|
+
# @param response_body [String] HTTP response body
|
88
|
+
# @return [Error] appropriate error instance
|
89
|
+
def self.from_response(status_code, message = nil, response_body = nil)
|
90
|
+
case status_code
|
91
|
+
when 400
|
92
|
+
ValidationError.new(message, status_code: status_code, response_body: response_body)
|
93
|
+
when 401
|
94
|
+
AuthenticationError.new(message, status_code: status_code, response_body: response_body)
|
95
|
+
when 403
|
96
|
+
AuthorizationError.new(message, status_code: status_code, response_body: response_body)
|
97
|
+
when 404
|
98
|
+
NotFoundError.new(message, status_code: status_code, response_body: response_body)
|
99
|
+
when 409
|
100
|
+
ConflictError.new(message, status_code: status_code, response_body: response_body)
|
101
|
+
when 429
|
102
|
+
RateLimitError.new(message, status_code: status_code, response_body: response_body)
|
103
|
+
when 400..499
|
104
|
+
ClientError.new(message, status_code: status_code, response_body: response_body)
|
105
|
+
when 500..599
|
106
|
+
ServerError.new(message, status_code: status_code, response_body: response_body)
|
107
|
+
else
|
108
|
+
Error.new(message, status_code: status_code, response_body: response_body)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|