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,259 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourceSpace
4
+ # Search interface for ResourceSpace API
5
+ #
6
+ # @example
7
+ # search = client.search
8
+ #
9
+ # # Basic search
10
+ # results = search.do_search("cat")
11
+ #
12
+ # # Advanced search with parameters
13
+ # results = search.do_search("web assets", {
14
+ # order_by: "date",
15
+ # sort: "desc",
16
+ # fetchrows: 20
17
+ # })
18
+ #
19
+ # # Search with previews
20
+ # results = search.search_get_previews("images", {
21
+ # getsizes: "col,thm,scr",
22
+ # fetchrows: 10
23
+ # })
24
+ class Search
25
+ # @return [Client] the ResourceSpace client
26
+ attr_reader :client
27
+
28
+ # Initialize the search interface
29
+ #
30
+ # @param client [Client] ResourceSpace client instance
31
+ def initialize(client)
32
+ @client = client
33
+ end
34
+
35
+ # Perform a basic search
36
+ #
37
+ # @param search_term [String] search term
38
+ # @param options [Hash] search options
39
+ # @option options [String] :restypes resource types to search (e.g., "1,2,3")
40
+ # @option options [String] :order_by field to order by ("relevance", "popularity", "date", "colour", "country", "title", "file_path", "resourceid", "extension", "user", "created")
41
+ # @option options [String] :sort sort direction ("asc" or "desc")
42
+ # @option options [Integer] :offset starting offset for results
43
+ # @option options [Integer] :fetchrows number of results to fetch
44
+ # @option options [String] :archive archive status ("0" = live resources, "1" = archived, "2" = both)
45
+ # @option options [Integer] :daylimit only return resources modified in the last X days
46
+ # @return [Hash] search results
47
+ def do_search(search_term, options = {})
48
+ params = build_search_params(search_term, options)
49
+ client.get("do_search", params)
50
+ end
51
+
52
+ # Search and get previews in one call
53
+ #
54
+ # @param search_term [String] search term
55
+ # @param options [Hash] search options
56
+ # @option options [String] :getsizes image sizes to include ("col,thm,scr,pre")
57
+ # @option options [String] :order_by field to order by
58
+ # @option options [String] :sort sort direction ("asc" or "desc")
59
+ # @option options [Integer] :fetchrows number of results to fetch
60
+ # @option options [String] :archive archive status
61
+ # @return [Hash] search results with preview data
62
+ def search_get_previews(search_term, options = {})
63
+ params = build_search_params(search_term, options)
64
+ params[:param6] = options[:getsizes] if options[:getsizes]
65
+
66
+ client.get("search_get_previews", params)
67
+ end
68
+
69
+ # Search for web assets (images, CSS, JS, fonts)
70
+ #
71
+ # @param asset_type [String] type of web asset ("image", "css", "javascript", "font", "icon")
72
+ # @param options [Hash] search options
73
+ # @return [Hash] search results filtered for web assets
74
+ def search_web_assets(asset_type = nil, options = {})
75
+ search_terms = []
76
+
77
+ case asset_type&.downcase
78
+ when "image", "images"
79
+ search_terms << "extension:jpg OR extension:jpeg OR extension:png OR extension:gif OR extension:svg OR extension:webp"
80
+ when "css", "stylesheet", "stylesheets"
81
+ search_terms << "extension:css"
82
+ when "javascript", "js"
83
+ search_terms << "extension:js"
84
+ when "font", "fonts"
85
+ search_terms << "extension:woff OR extension:woff2 OR extension:ttf OR extension:otf OR extension:eot"
86
+ when "icon", "icons"
87
+ search_terms << "extension:ico OR extension:svg"
88
+ else
89
+ # Search for all common web asset types
90
+ search_terms << "extension:jpg OR extension:jpeg OR extension:png OR extension:gif OR extension:svg OR extension:webp OR extension:css OR extension:js OR extension:woff OR extension:woff2 OR extension:ico"
91
+ end
92
+
93
+ search_term = search_terms.join(" OR ")
94
+ search_term += " #{options.delete(:query)}" if options[:query]
95
+
96
+ do_search(search_term, options)
97
+ end
98
+
99
+ # Search resources by file extension
100
+ #
101
+ # @param extensions [String, Array] file extension(s) to search for
102
+ # @param options [Hash] search options
103
+ # @return [Hash] search results
104
+ def search_by_extension(extensions, options = {})
105
+ extensions = Array(extensions).map(&:to_s)
106
+ search_term = extensions.map { |ext| "extension:#{ext.gsub(/^\./, '')}" }.join(" OR ")
107
+
108
+ do_search(search_term, options)
109
+ end
110
+
111
+ # Search resources by date range
112
+ #
113
+ # @param from_date [Date, String] start date (YYYY-MM-DD format)
114
+ # @param to_date [Date, String] end date (YYYY-MM-DD format)
115
+ # @param options [Hash] search options
116
+ # @return [Hash] search results
117
+ def search_by_date_range(from_date, to_date = nil, options = {})
118
+ from_str = format_date(from_date)
119
+ to_str = to_date ? format_date(to_date) : from_str
120
+
121
+ search_term = "created:#{from_str}"
122
+ search_term += ";#{to_str}" if to_date
123
+
124
+ do_search(search_term, options)
125
+ end
126
+
127
+ # Search resources by collection
128
+ #
129
+ # @param collection_id [Integer] collection ID
130
+ # @param options [Hash] search options
131
+ # @return [Hash] search results
132
+ def search_by_collection(collection_id, options = {})
133
+ search_term = "!collection#{collection_id}"
134
+ do_search(search_term, options)
135
+ end
136
+
137
+ # Search resources by resource IDs
138
+ #
139
+ # @param resource_ids [Array<Integer>] array of resource IDs
140
+ # @param options [Hash] search options
141
+ # @return [Hash] search results
142
+ def search_by_ids(resource_ids, options = {})
143
+ ids = Array(resource_ids).join(":")
144
+ search_term = "!list#{ids}"
145
+ do_search(search_term, options)
146
+ end
147
+
148
+ # Get recently added resources
149
+ #
150
+ # @param count [Integer] number of recent resources to return
151
+ # @param options [Hash] search options
152
+ # @return [Hash] search results
153
+ def recent_resources(count = 10, options = {})
154
+ search_term = "!last#{count}"
155
+ do_search(search_term, options)
156
+ end
157
+
158
+ # Search resources by tag
159
+ #
160
+ # @param tag [String] tag name
161
+ # @param options [Hash] search options
162
+ # @return [Hash] search results
163
+ def search_by_tag(tag, options = {})
164
+ search_term = "tag:#{tag}"
165
+ do_search(search_term, options)
166
+ end
167
+
168
+ # Search resources by user
169
+ #
170
+ # @param username [String] username
171
+ # @param options [Hash] search options
172
+ # @return [Hash] search results
173
+ def search_by_user(username, options = {})
174
+ search_term = "user:#{username}"
175
+ do_search(search_term, options)
176
+ end
177
+
178
+ # Search resources by title/name
179
+ #
180
+ # @param title [String] resource title
181
+ # @param options [Hash] search options
182
+ # @return [Hash] search results
183
+ def search_by_title(title, options = {})
184
+ search_term = "title:#{title}"
185
+ do_search(search_term, options)
186
+ end
187
+
188
+ # Advanced search with multiple criteria
189
+ #
190
+ # @param criteria [Hash] search criteria
191
+ # @option criteria [String] :title title search
192
+ # @option criteria [String] :tag tag search
193
+ # @option criteria [String] :user user search
194
+ # @option criteria [Array<String>] :extensions file extensions
195
+ # @option criteria [String] :from_date start date
196
+ # @option criteria [String] :to_date end date
197
+ # @param options [Hash] search options
198
+ # @return [Hash] search results
199
+ def advanced_search(criteria = {}, options = {})
200
+ search_parts = []
201
+
202
+ search_parts << "title:#{criteria[:title]}" if criteria[:title]
203
+ search_parts << "tag:#{criteria[:tag]}" if criteria[:tag]
204
+ search_parts << "user:#{criteria[:user]}" if criteria[:user]
205
+
206
+ if criteria[:extensions]
207
+ ext_search = Array(criteria[:extensions]).map { |ext| "extension:#{ext.gsub(/^\./, '')}" }.join(" OR ")
208
+ search_parts << "(#{ext_search})"
209
+ end
210
+
211
+ if criteria[:from_date]
212
+ date_search = "created:#{format_date(criteria[:from_date])}"
213
+ date_search += ";#{format_date(criteria[:to_date])}" if criteria[:to_date]
214
+ search_parts << date_search
215
+ end
216
+
217
+ search_term = search_parts.join(" AND ")
218
+ search_term = criteria[:query] if search_term.empty? && criteria[:query]
219
+
220
+ do_search(search_term, options)
221
+ end
222
+
223
+ private
224
+
225
+ # Build search parameters hash
226
+ #
227
+ # @param search_term [String] search term
228
+ # @param options [Hash] search options
229
+ # @return [Hash] parameters hash
230
+ def build_search_params(search_term, options = {})
231
+ params = { param1: search_term }
232
+
233
+ params[:param2] = options[:restypes] if options[:restypes]
234
+ params[:param3] = options[:order_by] if options[:order_by]
235
+ params[:param4] = options[:offset] if options[:offset]
236
+ params[:param5] = options[:fetchrows] if options[:fetchrows]
237
+ params[:param6] = options[:sort] if options[:sort]
238
+ params[:param7] = options[:archive] if options[:archive]
239
+ params[:param8] = options[:daylimit] if options[:daylimit]
240
+
241
+ params
242
+ end
243
+
244
+ # Format date for ResourceSpace API
245
+ #
246
+ # @param date [Date, String] date to format
247
+ # @return [String] formatted date string
248
+ def format_date(date)
249
+ case date
250
+ when Date
251
+ date.strftime("%Y-%m-%d")
252
+ when Time
253
+ date.strftime("%Y-%m-%d")
254
+ else
255
+ date.to_s
256
+ end
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,188 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourceSpace
4
+ # User management interface for ResourceSpace API
5
+ #
6
+ # @example
7
+ # users = client.users
8
+ #
9
+ # # Get user list
10
+ # all_users = users.get_users
11
+ #
12
+ # # Check permissions
13
+ # can_edit = users.check_permission("r")
14
+ class User
15
+ # @return [Client] the ResourceSpace client
16
+ attr_reader :client
17
+
18
+ # Initialize the user interface
19
+ #
20
+ # @param client [Client] ResourceSpace client instance
21
+ def initialize(client)
22
+ @client = client
23
+ end
24
+
25
+ # Get list of users
26
+ #
27
+ # @return [Array] array of user data
28
+ def get_users
29
+ client.get("get_users")
30
+ end
31
+
32
+ # Get users by permission
33
+ #
34
+ # @param permission [String] permission to check
35
+ # @return [Array] users with the specified permission
36
+ def get_users_by_permission(permission)
37
+ client.get("get_users_by_permission", { param1: permission })
38
+ end
39
+
40
+ # Check if current user has a permission
41
+ #
42
+ # @param permission [String] permission to check
43
+ # @return [Boolean] true if user has permission
44
+ def check_permission(permission)
45
+ response = client.get("checkperm", { param1: permission })
46
+ response == true || response == "true" || response == 1 || response == "1"
47
+ end
48
+
49
+ # Login and get a session key
50
+ #
51
+ # @param username [String] username
52
+ # @param password [String] password
53
+ # @return [String] session key for subsequent requests
54
+ def login(username, password)
55
+ response = client.get("login", {
56
+ param1: username,
57
+ param2: password
58
+ })
59
+
60
+ # The response should be a session key
61
+ response.is_a?(Hash) ? response["key"] || response["session_key"] : response
62
+ end
63
+
64
+ # Mark an email as invalid
65
+ #
66
+ # @param email [String] email address to mark as invalid
67
+ # @return [Hash] response
68
+ def mark_email_as_invalid(email)
69
+ client.post("mark_email_as_invalid", { param1: email })
70
+ end
71
+
72
+ # Get user message
73
+ #
74
+ # @param message_id [Integer] message ID
75
+ # @return [Hash] message details
76
+ def get_user_message(message_id)
77
+ client.get("get_user_message", { param1: message_id.to_s })
78
+ end
79
+
80
+ # Check if user can access a specific resource
81
+ #
82
+ # @param resource_id [Integer] resource ID
83
+ # @return [Boolean] true if user can access the resource
84
+ def can_access_resource?(resource_id)
85
+ begin
86
+ access_level = client.resources.get_resource_access(resource_id)
87
+ access_level >= 0 # 0 = open access, -1 = no access
88
+ rescue NotFoundError, AuthorizationError
89
+ false
90
+ end
91
+ end
92
+
93
+ # Check if user can edit a specific resource
94
+ #
95
+ # @param resource_id [Integer] resource ID
96
+ # @return [Boolean] true if user can edit the resource
97
+ def can_edit_resource?(resource_id)
98
+ client.resources.edit_access?(resource_id)
99
+ end
100
+
101
+ # Get current user information
102
+ #
103
+ # @return [Hash] current user data
104
+ def current_user
105
+ # Note: ResourceSpace API doesn't have a direct "current user" endpoint
106
+ # This would typically be implemented by getting user info based on the authenticated user
107
+ # For now, we'll use the username from configuration and search for it
108
+ users = get_users
109
+ users.find { |user| user["username"] == client.config.user }
110
+ end
111
+
112
+ # Check multiple permissions at once
113
+ #
114
+ # @param permissions [Array<String>] array of permissions to check
115
+ # @return [Hash] hash of permission => boolean pairs
116
+ def check_permissions(permissions)
117
+ result = {}
118
+ Array(permissions).each do |permission|
119
+ result[permission] = check_permission(permission)
120
+ end
121
+ result
122
+ end
123
+
124
+ # Get users with administrative privileges
125
+ #
126
+ # @return [Array] admin users
127
+ def get_admin_users
128
+ # Typically admin users have 'a' permission
129
+ get_users_by_permission("a")
130
+ end
131
+
132
+ # Check if current user is an admin
133
+ #
134
+ # @return [Boolean] true if user is admin
135
+ def admin?
136
+ check_permission("a")
137
+ end
138
+
139
+ # Check if current user can manage users
140
+ #
141
+ # @return [Boolean] true if user can manage users
142
+ def can_manage_users?
143
+ check_permission("u")
144
+ end
145
+
146
+ # Check if current user can manage collections
147
+ #
148
+ # @return [Boolean] true if user can manage collections
149
+ def can_manage_collections?
150
+ check_permission("k")
151
+ end
152
+
153
+ # Check if current user can upload files
154
+ #
155
+ # @return [Boolean] true if user can upload files
156
+ def can_upload?
157
+ check_permission("c")
158
+ end
159
+
160
+ # Check if current user can download files
161
+ #
162
+ # @return [Boolean] true if user can download files
163
+ def can_download?
164
+ check_permission("d")
165
+ end
166
+
167
+ # Check if current user can edit resources
168
+ #
169
+ # @return [Boolean] true if user can edit resources
170
+ def can_edit_resources?
171
+ check_permission("e")
172
+ end
173
+
174
+ # Get user capabilities summary
175
+ #
176
+ # @return [Hash] summary of user capabilities
177
+ def capabilities
178
+ {
179
+ admin: admin?,
180
+ manage_users: can_manage_users?,
181
+ manage_collections: can_manage_collections?,
182
+ upload: can_upload?,
183
+ download: can_download?,
184
+ edit_resources: can_edit_resources?
185
+ }
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourceSpace
4
+ # The current version of the ResourceSpace Ruby gem
5
+ VERSION = "0.1.0"
6
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "resourcespace/version"
4
+ require_relative "resourcespace/client"
5
+ require_relative "resourcespace/configuration"
6
+ require_relative "resourcespace/errors"
7
+ require_relative "resourcespace/resource"
8
+ require_relative "resourcespace/collection"
9
+ require_relative "resourcespace/search"
10
+ require_relative "resourcespace/user"
11
+ require_relative "resourcespace/metadata"
12
+
13
+ # ResourceSpace Ruby client for interacting with ResourceSpace Digital Asset Management API
14
+ #
15
+ # @example Basic usage
16
+ # client = ResourceSpace::Client.new(
17
+ # url: "https://your-resourcespace.com/api/",
18
+ # user: "your_username",
19
+ # private_key: "your_private_key"
20
+ # )
21
+ #
22
+ # # Search for resources
23
+ # results = client.search.do_search("cat")
24
+ #
25
+ # # Upload a file
26
+ # resource = client.resources.create_resource(
27
+ # name: "My Image",
28
+ # file: File.open("path/to/image.jpg")
29
+ # )
30
+ #
31
+ # @see https://www.resourcespace.com/knowledge-base/api/
32
+ module ResourceSpace
33
+ class << self
34
+ # Global configuration for the ResourceSpace gem
35
+ #
36
+ # @return [Configuration] the global configuration instance
37
+ attr_accessor :configuration
38
+
39
+ # Configure the ResourceSpace gem globally
40
+ #
41
+ # @yield [Configuration] the configuration instance
42
+ # @return [Configuration] the updated configuration
43
+ #
44
+ # @example
45
+ # ResourceSpace.configure do |config|
46
+ # config.url = "https://your-resourcespace.com/api/"
47
+ # config.user = "your_username"
48
+ # config.private_key = "your_private_key"
49
+ # config.timeout = 30
50
+ # end
51
+ def configure
52
+ self.configuration ||= Configuration.new
53
+ yield(configuration) if block_given?
54
+ configuration
55
+ end
56
+
57
+ # Get the current configuration or create a new one
58
+ #
59
+ # @return [Configuration] the configuration instance
60
+ def config
61
+ self.configuration ||= Configuration.new
62
+ end
63
+
64
+ # Reset the configuration to defaults
65
+ #
66
+ # @return [Configuration] a new configuration instance
67
+ def reset_config!
68
+ self.configuration = Configuration.new
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "resourcespace-ruby"
5
+ spec.version = "0.1.0"
6
+ spec.authors = ["Survey Flunkie Team"]
7
+ spec.email = ["info@surveyflunkie.com"]
8
+
9
+ spec.summary = "Ruby client for ResourceSpace Digital Asset Management API"
10
+ spec.description = "A comprehensive Ruby client library for interacting with ResourceSpace open-source Digital Asset Management system. Supports resource management, file uploads, searching, collections, and metadata operations."
11
+ spec.homepage = "https://github.com/survey-flunkie/resourcespace-ruby"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = ">= 3.1.0"
14
+
15
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = "https://github.com/survey-flunkie/resourcespace-ruby"
18
+ spec.metadata["changelog_uri"] = "https://github.com/survey-flunkie/resourcespace-ruby/blob/main/CHANGELOG.md"
19
+ spec.metadata["documentation_uri"] = "https://rubydoc.info/gems/resourcespace-ruby"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ spec.files = Dir.chdir(__dir__) do
23
+ `git ls-files -z`.split("\x0").reject do |f|
24
+ (File.expand_path(f) == __FILE__) ||
25
+ f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile])
26
+ end
27
+ end
28
+
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ # Runtime dependencies
34
+ spec.add_dependency "faraday", "~> 2.7"
35
+ spec.add_dependency "faraday-multipart", "~> 1.0"
36
+ spec.add_dependency "mime-types", "~> 3.4"
37
+ spec.add_dependency "json", "~> 2.6"
38
+
39
+ # Development dependencies
40
+ spec.add_development_dependency "bundler", "~> 2.0"
41
+ spec.add_development_dependency "rake", "~> 13.0"
42
+ spec.add_development_dependency "rspec", "~> 3.12"
43
+ spec.add_development_dependency "webmock", "~> 3.18"
44
+ spec.add_development_dependency "vcr", "~> 6.1"
45
+ spec.add_development_dependency "simplecov", "~> 0.22"
46
+ spec.add_development_dependency "rubocop", "~> 1.50"
47
+ spec.add_development_dependency "rubocop-rspec", "~> 2.20"
48
+ spec.add_development_dependency "yard", "~> 0.9"
49
+ end