onlyoffice-docs_integration_sdk 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.
Files changed (31) hide show
  1. checksums.yaml +7 -0
  2. data/lib/onlyoffice/docs_integration_sdk/document_editor/config.rb +1479 -0
  3. data/lib/onlyoffice/docs_integration_sdk/document_editor/config_test.rb +1713 -0
  4. data/lib/onlyoffice/docs_integration_sdk/document_editor.rb +29 -0
  5. data/lib/onlyoffice/docs_integration_sdk/document_server/client/command.rb +417 -0
  6. data/lib/onlyoffice/docs_integration_sdk/document_server/client/command_test.rb +672 -0
  7. data/lib/onlyoffice/docs_integration_sdk/document_server/client/conversion.rb +477 -0
  8. data/lib/onlyoffice/docs_integration_sdk/document_server/client/conversion_test.rb +682 -0
  9. data/lib/onlyoffice/docs_integration_sdk/document_server/client/healthcheck.rb +101 -0
  10. data/lib/onlyoffice/docs_integration_sdk/document_server/client/healthcheck_test.rb +209 -0
  11. data/lib/onlyoffice/docs_integration_sdk/document_server/client/jwt.rb +116 -0
  12. data/lib/onlyoffice/docs_integration_sdk/document_server/client/jwt_test.rb +70 -0
  13. data/lib/onlyoffice/docs_integration_sdk/document_server/client/response.rb +73 -0
  14. data/lib/onlyoffice/docs_integration_sdk/document_server/client/response_test.rb +49 -0
  15. data/lib/onlyoffice/docs_integration_sdk/document_server/client/service.rb +44 -0
  16. data/lib/onlyoffice/docs_integration_sdk/document_server/client/ua.rb +31 -0
  17. data/lib/onlyoffice/docs_integration_sdk/document_server/client/ua_test.rb +35 -0
  18. data/lib/onlyoffice/docs_integration_sdk/document_server/client.rb +321 -0
  19. data/lib/onlyoffice/docs_integration_sdk/document_server/client_test.rb +1259 -0
  20. data/lib/onlyoffice/docs_integration_sdk/document_server.rb +29 -0
  21. data/lib/onlyoffice/docs_integration_sdk/document_storage/callback.rb +276 -0
  22. data/lib/onlyoffice/docs_integration_sdk/document_storage/callback_test.rb +291 -0
  23. data/lib/onlyoffice/docs_integration_sdk/document_storage.rb +29 -0
  24. data/lib/onlyoffice/docs_integration_sdk/jwt.rb +448 -0
  25. data/lib/onlyoffice/docs_integration_sdk/jwt_test.rb +598 -0
  26. data/lib/onlyoffice/docs_integration_sdk/test_test.rb +113 -0
  27. data/lib/onlyoffice/docs_integration_sdk/version.rb +26 -0
  28. data/lib/onlyoffice/docs_integration_sdk/version_test.rb +33 -0
  29. data/lib/onlyoffice/docs_integration_sdk.rb +31 -0
  30. data/lib/onlyoffice.rb +21 -0
  31. metadata +283 -0
@@ -0,0 +1,35 @@
1
+ #
2
+ # (c) Copyright Ascensio System SIA 2025
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ # typed: true
18
+ # frozen_string_literal: true
19
+
20
+ require "test/unit"
21
+ require_relative "ua"
22
+
23
+ module Onlyoffice
24
+ module DocsIntegrationSdk
25
+ module DocumentServer
26
+ class Client
27
+ class UserAgentTest < ::Test::Unit::TestCase
28
+ def test
29
+ assert_equal("com.onlyoffice.docs-integration-sdk-ruby #{VERSION}", USER_AGENT)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,321 @@
1
+ #
2
+ # (c) Copyright Ascensio System SIA 2025
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ # typed: strict
18
+ # frozen_string_literal: true
19
+
20
+ require "json"
21
+ require "net/http"
22
+ require "sorbet-runtime"
23
+ require_relative "client/command"
24
+ require_relative "client/conversion"
25
+ require_relative "client/healthcheck"
26
+ require_relative "client/jwt"
27
+ require_relative "client/response"
28
+ require_relative "client/service"
29
+ require_relative "client/ua"
30
+
31
+ module Onlyoffice
32
+ module DocsIntegrationSdk
33
+ module DocumentServer
34
+ # Client is a class that provides a way to interact with the Document
35
+ # Server API. It acts as a wrapper around the Net::HTTP class, offering a
36
+ # more convenient method for interacting with the API.
37
+ #
38
+ # @since 0.1.0
39
+ class Client
40
+ extend T::Sig
41
+
42
+ # http is a Net::HTTP that is used to make requests to the Document
43
+ # Server. This should only be used for requests to the Document Server,
44
+ # because requests may contain a JWT token. It stores a shallow copy of
45
+ # the original instance.
46
+ #
47
+ # @since 0.1.0
48
+ sig {returns(Net::HTTP)}
49
+ def http
50
+ @http.clone
51
+ end
52
+
53
+ # @since 0.1.0
54
+ sig {returns(Net::HTTP)}
55
+ protected def http!
56
+ @http
57
+ end
58
+
59
+ # base_uri is a base URL of the Document Server. It is used to build the
60
+ # full URL of the request. It stores a shallow copy of the original
61
+ # instance.
62
+ #
63
+ # @since 0.1.0
64
+ sig {returns(URI::HTTP)}
65
+ def base_uri
66
+ @base_uri.clone
67
+ end
68
+
69
+ # user_agent is a User-Agent that is used to make requests to the
70
+ # Document Server.
71
+ #
72
+ # @since 0.1.0
73
+ sig {returns(String)}
74
+ def user_agent
75
+ @user_agent
76
+ end
77
+
78
+ # command is a CommandService that is used to interact with the Command
79
+ # Service API.
80
+ #
81
+ # @since 0.1.0
82
+ sig {returns(CommandService)}
83
+ attr_reader :command
84
+
85
+ # conversion is a ConversionService that is used to interact with the
86
+ # Conversion Service API.
87
+ #
88
+ # @since 0.1.0
89
+ sig {returns(ConversionService)}
90
+ attr_reader :conversion
91
+
92
+ # healthcheck is a HealthcheckService that is used to interact with the
93
+ # Healthcheck Service API.
94
+ #
95
+ # @since 0.1.0
96
+ sig {returns(HealthcheckService)}
97
+ attr_reader :healthcheck
98
+
99
+ # initialize initializes a new Client instance. It requires either http
100
+ # or base_uri to be provided. If only one of them is provided, the other
101
+ # one will be built from the provided one. If user_agent is not
102
+ # provided, it will default to the {USER_AGENT} constant. It makes a
103
+ # shallow copy of the provided instances.
104
+ #
105
+ # @param http
106
+ # The Net::HTTP instance that is used to make requests to the Document
107
+ # Server.
108
+ # @param base_uri
109
+ # The base URI of the Document Server.
110
+ # @param user_agent
111
+ # The User-Agent that is used to make requests to the Document Server.
112
+ #
113
+ # @raise [ArgumentError] If neither http nor base_uri is provided.
114
+ #
115
+ # @since 0.1.0
116
+ sig {params(http: T.nilable(Net::HTTP), base_uri: T.nilable(URI::HTTP), user_agent: T.nilable(String)).void}
117
+ def initialize(http: nil, base_uri: nil, user_agent: nil)
118
+ if !http && !base_uri
119
+ raise ArgumentError, "Either http or base_uri must be provided"
120
+ end
121
+
122
+ if http && base_uri
123
+ @http = T.let(http.clone, Net::HTTP)
124
+ @base_uri = T.let(base_uri.clone, URI::HTTP)
125
+ elsif http
126
+ @http = T.let(http.clone, Net::HTTP)
127
+ @base_uri = T.let(URI::HTTP.build(host: @http.address, port: @http.port), URI::HTTP)
128
+ elsif base_uri
129
+ @http = T.let(Net::HTTP.new(base_uri.host, base_uri.port), Net::HTTP)
130
+ @base_uri = T.let(base_uri.clone, URI::HTTP)
131
+ else
132
+ # :nocov:
133
+ # unreachable
134
+ # :nocov:
135
+ end
136
+
137
+ if user_agent
138
+ @user_agent = T.let(user_agent, String)
139
+ else
140
+ @user_agent = T.let(USER_AGENT, String)
141
+ end
142
+
143
+ @command = T.let(CommandService.new(client: self), CommandService)
144
+ @conversion = T.let(ConversionService.new(client: self), ConversionService)
145
+ @healthcheck = T.let(HealthcheckService.new(client: self), HealthcheckService)
146
+ end
147
+
148
+ # with_jwt creates a new Client instance with the provided JWT
149
+ # configuration. It modifies the Net::HTTP#request method to add the JWT
150
+ # token to the request. The JWT token is added to the request based on
151
+ # the locations provided in the JWT configuration.
152
+ #
153
+ # @param jwt The JWT configuration that is used to sign requests.
154
+ # @return A new Client instance with the JWT configuration applied.
155
+ # @since 0.1.0
156
+ sig {params(jwt: Jwt).returns(Client)}
157
+ def with_jwt(jwt)
158
+ # The idea of this approach has its roots in the practice of Go, where
159
+ # you can implement your own http.Transport. Unfortunately, Ruby does
160
+ # not have a direct equivalent of http.Transport, so you have to create
161
+ # a sort of patch for the request method.
162
+ #
163
+ # https://pkg.go.dev/net/http@go1.23.5/#Transport
164
+ # https://github.com/ruby/ruby/blob/v3_4_1/lib/net/http.rb/#L2367
165
+
166
+ r = @http.method(:request)
167
+ c = copy
168
+
169
+ c.http!.define_singleton_method(:request) do |req, body = nil, &block|
170
+ req = T.let(req.clone, Net::HTTPRequest)
171
+
172
+ if (req.body || req.body_stream) && body
173
+ # Leave it untouched so Ruby can raise an error.
174
+ # https://github.com/ruby/ruby/blob/v3_4_1/lib/net/http/generic_request.rb/#L186
175
+ elsif req.body
176
+ if !jwt.locations.empty?
177
+ b = JSON.parse(req.body)
178
+
179
+ if jwt.locations.include?(Jwt::Location::Header)
180
+ p = jwt.jwt.encode_header(b)
181
+ req[jwt.header] = "#{jwt.schema} #{p}"
182
+ end
183
+
184
+ if jwt.locations.include?(Jwt::Location::Body)
185
+ p = jwt.jwt.encode_body(b)
186
+ req.body = p.to_json
187
+ end
188
+ end
189
+ elsif req.body_stream
190
+ # There are doubts regarding the necessity of implementing this
191
+ # branch.
192
+ elsif body
193
+ if !jwt.locations.empty?
194
+ b = JSON.parse(body)
195
+
196
+ if jwt.locations.include?(Jwt::Location::Header)
197
+ p = jwt.jwt.encode_header(b)
198
+ req[jwt.header] = "#{jwt.schema} #{p}"
199
+ end
200
+
201
+ if jwt.locations.include?(Jwt::Location::Body)
202
+ p = jwt.jwt.encode_body(b)
203
+ body = p.to_json
204
+ end
205
+ end
206
+ end
207
+
208
+ r.call(req, body, &block)
209
+ end
210
+
211
+ c
212
+ end
213
+
214
+ # @since 0.1.0
215
+ sig {returns(Client)}
216
+ protected def copy
217
+ self.class.new(
218
+ base_uri: @base_uri,
219
+ http: @http,
220
+ user_agent: @user_agent,
221
+ )
222
+ end
223
+
224
+ # get makes a GET request to the Document Server. It is a wrapper around
225
+ # the {uri}, {request} and {do} methods.
226
+ #
227
+ # @param p The path to join with the base URI.
228
+ # @return Inherited from {do}.
229
+ # @since 0.1.0
230
+ sig {params(p: String).returns([T.untyped, Response])}
231
+ def get(p)
232
+ u = uri(p)
233
+ r = request(Net::HTTP::Get, u)
234
+ self.do(r)
235
+ end
236
+
237
+ # post makes a POST request to the Document Server. It is a wrapper
238
+ # around the {uri}, {request} and {do} methods.
239
+ #
240
+ # @param p The path to join with the base URI.
241
+ # @param b The body of the request.
242
+ # @return Inherited from {do}
243
+ # @since 0.1.0
244
+ sig {params(p: String, b: T.untyped).returns([T.untyped, Response])}
245
+ def post(p, b = nil)
246
+ u = uri(p)
247
+ r = request(Net::HTTP::Post, u, b)
248
+ self.do(r)
249
+ end
250
+
251
+ # uri creates a new URI::HTTP instance by joining the base URI with the
252
+ # provided path.
253
+ #
254
+ # @param p The path to join with the base URI.
255
+ # @return A new URI::HTTP instance.
256
+ # @since 0.1.0
257
+ sig {params(p: String).returns(URI::HTTP)}
258
+ def uri(p)
259
+ # The URI.join returns a URI in the same implementation as the first
260
+ # argument. Therefore, calling T.cast is safe because the @base_url is a
261
+ # URI::HTTP and the result will be a URI::HTTP.
262
+ T.cast(URI.join(@base_uri.to_s, p), URI::HTTP)
263
+ end
264
+
265
+ # request creates a new Net::HTTPRequest instance with the provided
266
+ # method, URI, and body.
267
+ #
268
+ # @param m The method of the request.
269
+ # @param u The URI of the request.
270
+ # @param b The body of the request.
271
+ # @return A new Net::HTTPRequest instance.
272
+ # @since 0.1.0
273
+ sig {params(m: T.class_of(Net::HTTPRequest), u: URI::HTTP, b: T.untyped).returns(Net::HTTPRequest)}
274
+ def request(m, u, b = nil)
275
+ r = m.new(u)
276
+
277
+ r["Accept"] = "application/json"
278
+ r["User-Agent"] = @user_agent
279
+
280
+ if b
281
+ r["Content-Type"] = "application/json"
282
+ r.body = b.to_json
283
+ end
284
+
285
+ r
286
+ end
287
+
288
+ # do makes a request to the Document Server. It returns a tuple with the
289
+ # body of the response and the response instance.
290
+ #
291
+ # @param req
292
+ # The Net::HTTPRequest that is used to make the request.
293
+ #
294
+ # @return
295
+ # A tuple with the body of the response and the response instance.
296
+ #
297
+ # @since 0.1.0
298
+ sig {params(req: Net::HTTPRequest).returns([T.untyped, Response])}
299
+ def do(req)
300
+ err = T.let(nil, T.untyped)
301
+ b = T.let(nil, T.untyped)
302
+
303
+ # Document Server always returns a response with the status 200, so
304
+ # there is no need to check for any other statuses.
305
+
306
+ raw = T.let(@http.request(req), Net::HTTPResponse)
307
+
308
+ begin
309
+ b = JSON.parse(raw.body)
310
+ rescue StandardError => e
311
+ err = e
312
+ end
313
+
314
+ res = Response.new(request: req, response: raw, error: err)
315
+
316
+ [b, res]
317
+ end
318
+ end
319
+ end
320
+ end
321
+ end