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.
@@ -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