sp-job 0.2.3 → 0.3.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/configure +40 -0
  4. data/lib/sp-job.rb +21 -2
  5. data/lib/sp/job/back_burner.rb +350 -68
  6. data/lib/sp/job/broker.rb +18 -16
  7. data/lib/sp/job/broker_http_client.rb +80 -20
  8. data/lib/sp/job/broker_oauth2_client.rb +12 -4
  9. data/lib/sp/job/common.rb +876 -62
  10. data/lib/sp/job/configure/configure.rb +640 -0
  11. data/lib/sp/job/curl_http_client.rb +100 -0
  12. data/lib/sp/job/easy_http_client.rb +94 -0
  13. data/lib/sp/job/http_client.rb +51 -0
  14. data/lib/sp/job/job_db_adapter.rb +38 -36
  15. data/lib/sp/job/jsonapi_error.rb +31 -74
  16. data/lib/sp/job/jwt.rb +55 -5
  17. data/lib/sp/job/mail_queue.rb +9 -2
  18. data/lib/sp/job/manticore_http_client.rb +94 -0
  19. data/lib/sp/job/pg_connection.rb +90 -10
  20. data/lib/sp/job/query_params.rb +45 -0
  21. data/lib/sp/job/rfc822.rb +13 -0
  22. data/lib/sp/job/session.rb +239 -0
  23. data/lib/sp/job/unique_file.rb +37 -1
  24. data/lib/sp/job/uploaded_image_converter.rb +27 -19
  25. data/lib/sp/job/worker.rb +51 -1
  26. data/lib/sp/job/worker_thread.rb +22 -7
  27. data/lib/sp/jsonapi.rb +24 -0
  28. data/lib/sp/jsonapi/adapters/base.rb +177 -0
  29. data/lib/sp/jsonapi/adapters/db.rb +26 -0
  30. data/lib/sp/jsonapi/adapters/raw_db.rb +96 -0
  31. data/lib/sp/jsonapi/exceptions.rb +54 -0
  32. data/lib/sp/jsonapi/model/base.rb +31 -0
  33. data/lib/sp/jsonapi/model/concerns/attributes.rb +91 -0
  34. data/lib/sp/jsonapi/model/concerns/model.rb +39 -0
  35. data/lib/sp/jsonapi/model/concerns/persistence.rb +212 -0
  36. data/lib/sp/jsonapi/model/concerns/serialization.rb +57 -0
  37. data/lib/sp/jsonapi/parameters.rb +54 -0
  38. data/lib/sp/jsonapi/service.rb +96 -0
  39. data/lib/tasks/configure.rake +2 -496
  40. data/sp-job.gemspec +3 -2
  41. metadata +24 -2
@@ -0,0 +1,100 @@
1
+ #
2
+ # Copyright (c) 2011-2016 Cloudware S.A. All rights reserved.
3
+ #
4
+ # This file is part of sp-job.
5
+ #
6
+ # sp-job is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Affero General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # sp-job is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Affero General Public License
17
+ # along with sp-job. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+ # encoding: utf-8
20
+ #
21
+
22
+ #
23
+ # A helper class to do HTTP request without session management.
24
+ #
25
+
26
+ require 'curb'
27
+ require_relative 'easy_http_client'
28
+ require_relative 'jsonapi_error'
29
+
30
+ module SP
31
+ module Job
32
+ class CurlHTTPClient < EasyHttpClient
33
+ def self.post(url:, headers:, body:, expect:, conn_options: {})
34
+ # since we're not auto-renew tokens, we can use a simple CURL request
35
+ conn_options[:connection_timeout] ||= 10
36
+ conn_options[:request_timeout] ||= 60
37
+ r = Curl::Easy.http_post(url, body) do |handle|
38
+ handle.connect_timeout = conn_options[:connection_timeout]
39
+ handle.timeout = conn_options[:request_timeout]
40
+ headers.each do |k,v|
41
+ handle.headers[k] = v
42
+ end
43
+ end
44
+ nr = self.normalize_response(curb_r: r)
45
+ # compare status code
46
+ if nr[:code] != expect[:code]
47
+ if 401 == nr[:code]
48
+ raise ::SP::Job::JSONAPI::Error.new(status: nr[:code], code: 'A01', detail: nil)
49
+ else
50
+ raise ::SP::Job::JSONAPI::Error.new(status: nr[:code], code: 'B01', detail: nil)
51
+ end
52
+ end
53
+ # compare content-type
54
+ if nr[:content][:type] != expect[:content][:type]
55
+ raise ::SP::Job::JSONAPI::Error.new(status: 500, code: 'I01', detail: "Unexpected 'Content-Type': #{nr[:content][:type]}, expected #{expect[:content][:type]}!")
56
+ end
57
+ # done
58
+ nr
59
+ end
60
+
61
+ def self.get(url:)
62
+ response = Curl::Easy.http_get(url)
63
+ self.normalize_response(curb_r: response)
64
+ end
65
+
66
+ def self.delete(url:, headers:)
67
+ response = Curl::Easy.http_delete(url, headers)
68
+ self.normalize_response(curb_r: response)
69
+ end
70
+
71
+ private
72
+
73
+ def self.normalize_response(curb_r:)
74
+ http_response, *http_headers = curb_r.header_str.split(/[\r\n]+/).map(&:strip)
75
+ o = {
76
+ code: curb_r.response_code,
77
+ body: curb_r.body,
78
+ description: http_reason(code: curb_r.response_code),
79
+ content: {
80
+ type: nil,
81
+ length: 0
82
+ }
83
+ }
84
+ http_headers.each do |header|
85
+ m = header.match("(^Content-Type){1}:\s(.*){1}")
86
+ if nil != m && 3 == m.length
87
+ o[:content][:type] = m[2]
88
+ end
89
+ m = header.match("(^Content-Length){1}:\s\([0-9]+){1}")
90
+ if nil != m && 3 == m.length
91
+ o[:content][:length] = m[2]
92
+ end
93
+ end
94
+ o
95
+ end
96
+
97
+
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,94 @@
1
+ #
2
+ # Copyright (c) 2011-2016 Cloudware S.A. All rights reserved.
3
+ #
4
+ # This file is part of sp-job.
5
+ #
6
+ # sp-job is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Affero General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # sp-job is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Affero General Public License
17
+ # along with sp-job. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+ # encoding: utf-8
20
+ #
21
+
22
+ module SP
23
+ module Job
24
+ class EasyHttpClient
25
+ @@REASONS = {
26
+ 100 => 'Continue',
27
+ 101 => 'Switching Protocols',
28
+ 102 => 'Processing',
29
+ 200 => 'OK',
30
+ 201 => 'Created',
31
+ 202 => 'Accepted',
32
+ 203 => 'Non-Authoritative Information',
33
+ 204 => 'No Content',
34
+ 205 => 'Reset Content',
35
+ 206 => 'Partial Content',
36
+ 207 => 'Multi-Status',
37
+ 226 => 'IM Used',
38
+ 300 => 'Multiple Choices',
39
+ 301 => 'Moved Permanently',
40
+ 302 => 'Found',
41
+ 303 => 'See Other',
42
+ 304 => 'Not Modified',
43
+ 305 => 'Use Proxy',
44
+ 306 => 'Reserved',
45
+ 307 => 'Temporary Redirect',
46
+ 308 => 'Permanent Redirect',
47
+ 400 => 'Bad Request',
48
+ 401 => 'Unauthorized',
49
+ 402 => 'Payment Required',
50
+ 403 => 'Forbidden',
51
+ 404 => 'Not Found',
52
+ 405 => 'Method Not Allowed',
53
+ 406 => 'Not Acceptable',
54
+ 407 => 'Proxy Authentication Required',
55
+ 408 => 'Request Timeout',
56
+ 409 => 'Conflict',
57
+ 410 => 'Gone',
58
+ 411 => 'Length Required',
59
+ 412 => 'Precondition Failed',
60
+ 413 => 'Request Entity Too Large',
61
+ 414 => 'Request-URI Too Long',
62
+ 415 => 'Unsupported Media Type',
63
+ 416 => 'Requested Range Not Satisfiable',
64
+ 417 => 'Expectation Failed',
65
+ 418 => "I'm a Teapot",
66
+ 422 => 'Unprocessable Entity',
67
+ 423 => 'Locked',
68
+ 424 => 'Failed Dependency',
69
+ 426 => 'Upgrade Required',
70
+ 500 => 'Internal Server Error',
71
+ 501 => 'Not Implemented',
72
+ 502 => 'Bad Gateway',
73
+ 503 => 'Service Unavailable',
74
+ 504 => 'Gateway Timeout',
75
+ 505 => 'HTTP Version Not Supported',
76
+ 506 => 'Variant Also Negotiates',
77
+ 507 => 'Insufficient Storage',
78
+ 510 => 'Not Extended'
79
+ }
80
+
81
+ def self.http_reason(code:)
82
+ return @@REASONS[code]
83
+ end
84
+
85
+ def self.post(url:, headers:, body:, expect:)
86
+ raise NotImplementedError
87
+ end
88
+
89
+ def self.get(url:)
90
+ raise NotImplementedError
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,51 @@
1
+ #
2
+ # Copyright (c) 2011-2016 Cloudware S.A. All rights reserved.
3
+ #
4
+ # This file is part of sp-job.
5
+ #
6
+ # sp-job is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Affero General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # sp-job is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Affero General Public License
17
+ # along with sp-job. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+ # encoding: utf-8
20
+ #
21
+
22
+ #
23
+ # A helper class to do HTTP request without session management.
24
+ #
25
+
26
+ require_relative 'curl_http_client' unless RUBY_ENGINE == 'jruby'
27
+ require_relative 'manticore_http_client' if RUBY_ENGINE == 'jruby'
28
+
29
+ module SP
30
+ module Job
31
+ class HttpClient < EasyHttpClient
32
+
33
+ def self.get_klass
34
+ RUBY_ENGINE == 'jruby' ? ManticoreHTTPClient : CurlHTTPClient
35
+ end
36
+
37
+ def self.post(url:, headers:, body:, expect:, conn_options: {})
38
+ get_klass.post(url: url, headers: headers, body: body, expect: expect, conn_options: conn_options)
39
+ end
40
+
41
+ def self.get(url:)
42
+ get_klass.get(url: url)
43
+ end
44
+
45
+ def self.delete(url:, headers:)
46
+ get_klass.delete(url: url, headers: headers)
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -1,60 +1,62 @@
1
1
  module SP
2
2
  module Job
3
3
 
4
- unless RUBY_ENGINE == 'jruby' # TODO suck in the base class from SP-DUH
5
-
6
- class JobDbAdapter < ::SP::Duh::JSONAPI::Adapters::Db
4
+ if RUBY_ENGINE == 'jruby' # TODO suck in the base class from SP-DUH
5
+ class JobDbAdapter < ::SP::JSONAPI::Adapters::Db
7
6
 
8
7
  private
9
8
 
10
9
  # Implement the JSONAPI request by direct querying of the JSONAPI function in the database
11
10
  def do_request_on_the_db(method, path, params)
12
- jsonapi_query = %Q[ SELECT * FROM public.jsonapi($1, $2, $3, $4, $5, $6, $7, $8, $9) ]
11
+ jsonapi_query = %Q[ SELECT * FROM public.jsonapi('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ]
13
12
 
14
- response = service.connection.exec jsonapi_query, method, (method == 'GET' ? url_with_params_for_query(path, params) : url(path)), (method == 'GET' ? '' : params_for_body(params)), user_id, company_id, company_schema, sharded_schema, accounting_schema, accounting_prefix
13
+ response = service.connection.exec jsonapi_query, method, (method == 'GET' ? url_with_params_for_query(path, params) : url(path)), (method == 'GET' ? '' : params_for_body(params)), user_id, entity_id, entity_schema, sharded_schema, subentity_schema, subentity_prefix
15
14
  response.first if response.first
16
15
  end
17
16
 
18
- def explicit_do_request_on_the_db(exp_accounting_schema, exp_accounting_prefix, method, path, params)
19
- jsonapi_query = %Q[ SELECT * FROM public.jsonapi($1, $2, $3, $4, $5, $6, $7, $8, $9) ]
17
+ def explicit_do_request_on_the_db(exp_subentity_schema, exp_subentity_prefix, method, path, params)
18
+ jsonapi_query = %Q[ SELECT * FROM public.jsonapi('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ]
20
19
 
21
- response = service.connection.exec jsonapi_query, method, (method == 'GET' ? url_with_params_for_query(path, params) : url(path)), (method == 'GET' ? '' : params_for_body(params)), user_id, company_id, company_schema, sharded_schema, exp_accounting_schema, exp_accounting_prefix
20
+ response = service.connection.exec jsonapi_query, method, (method == 'GET' ? url_with_params_for_query(path, params) : url(path)), (method == 'GET' ? '' : params_for_body(params)), user_id, entity_id, entity_schema, sharded_schema, exp_subentity_schema, exp_subentity_prefix
22
21
  response.first if response.first
23
22
  end
24
23
 
25
- def user_id ; service.parameters.user_id ; end
26
- def company_id ; service.parameters.company_id ; end
27
- def company_schema ; service.parameters.company_schema.nil? ? nil : service.parameters.company_schema ; end
28
- def sharded_schema ; service.parameters.sharded_schema.nil? ? nil : service.parameters.sharded_schema ; end
29
- def accounting_schema ; service.parameters.accounting_schema.nil? ? nil : service.parameters.accounting_schema ; end
30
- def accounting_prefix ; service.parameters.accounting_prefix.nil? ? nil : service.parameters.accounting_prefix ; end
24
+ def user_id ; service.parameters.user_id ; end
25
+ def entity_id ; service.parameters.entity_id ; end
26
+ def entity_schema ; service.parameters.entity_schema.nil? ? nil : service.parameters.entity_schema ; end
27
+ def sharded_schema ; service.parameters.sharded_schema.nil? ? nil : service.parameters.sharded_schema ; end
28
+ def subentity_schema ; service.parameters.subentity_schema.nil? ? nil : service.parameters.subentity_schema ; end
29
+ def subentity_prefix ; service.parameters.subentity_prefix.nil? ? nil : service.parameters.subentity_prefix ; end
30
+
31
+ end
32
+ else
33
+
34
+ class JobDbAdapter < ::SP::Duh::JSONAPI::Adapters::Db
35
+
36
+ private
31
37
 
32
- def params_for_body(params)
33
- params.blank? ? '' : params.to_json
38
+ # Implement the JSONAPI request by direct querying of the JSONAPI function in the database
39
+ def do_request_on_the_db(method, path, params)
40
+ jsonapi_query = %Q[ SELECT * FROM public.jsonapi('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ]
41
+
42
+ response = service.connection.exec jsonapi_query, method, (method == 'GET' ? url_with_params_for_query(path, params) : url(path)), (method == 'GET' ? '' : params_for_body(params)), user_id, entity_id, entity_schema, sharded_schema, subentity_schema, subentity_prefix
43
+ response.first if response.first
34
44
  end
35
45
 
36
- def params_for_query(params)
37
- query = ""
38
- if !params.blank?
39
- case
40
- when params.is_a?(Array)
41
- # query = params.join('&')
42
- query = params.map{ |v| URI.encode(URI.encode(v), "&") }.join('&')
43
- when params.is_a?(Hash)
44
- query = params.map do |k,v|
45
- if v.is_a?(String)
46
- "#{k}=\"#{URI.encode(URI.encode(v), "&")}\""
47
- else
48
- "#{k}=#{v}"
49
- end
50
- end.join('&')
51
- else
52
- query = params.to_s
53
- end
54
- end
55
- query
46
+ def explicit_do_request_on_the_db(exp_subentity_schema, exp_subentity_prefix, method, path, params)
47
+ jsonapi_query = %Q[ SELECT * FROM public.jsonapi('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ]
48
+
49
+ response = service.connection.exec jsonapi_query, method, (method == 'GET' ? url_with_params_for_query(path, params) : url(path)), (method == 'GET' ? '' : params_for_body(params)), user_id, entity_id, entity_schema, sharded_schema, exp_subentity_schema, exp_subentity_prefix
50
+ response.first if response.first
56
51
  end
57
52
 
53
+ def user_id ; service.parameters.user_id ; end
54
+ def entity_id ; service.parameters.entity_id ; end
55
+ def entity_schema ; service.parameters.entity_schema.nil? ? nil : service.parameters.entity_schema ; end
56
+ def sharded_schema ; service.parameters.sharded_schema.nil? ? nil : service.parameters.sharded_schema ; end
57
+ def subentity_schema ; service.parameters.subentity_schema.nil? ? nil : service.parameters.subentity_schema ; end
58
+ def subentity_prefix ; service.parameters.subentity_prefix.nil? ? nil : service.parameters.subentity_prefix ; end
59
+
58
60
  end
59
61
 
60
62
  end
@@ -7,88 +7,45 @@
7
7
  # Helper to obtain tokens to access toconline API's.
8
8
  #
9
9
 
10
+ require 'sp/job/common'
11
+
10
12
  module SP
11
13
  module Job
12
-
13
- #
14
- # Helper class to transform an error into json api format.
15
- #
16
- class JSONAPIError < StandardError
17
-
18
- # {
19
- # "errors": [
20
- # {
21
- # "status": nullptr,
22
- # "code": nullptr,
23
- # "detail": nullptr,
24
- # "meta": {
25
- # "internal-error": nullptr
26
- # }
27
- # }
28
- # ]
29
- # }
30
-
31
- private
32
-
33
- @error
34
-
35
- public
36
-
37
- def initialize (code: 500, detail: nil, internal: nil)
38
- @errors = [
39
- {
40
- :code => code,
41
- :detail => detail
14
+ module JSONAPI
15
+
16
+ class Error < ::SP::Job::Common::Exception
17
+ def initialize(status:, code:, detail:, internal:nil)
18
+ body = {
19
+ errors: [
20
+ {
21
+ code: "#{code}",
22
+ detail: "#{detail}",
23
+ status: "#{status} - #{::SP::Job::HttpClient.http_reason(code: status)}"
24
+ }
25
+ ]
42
26
  }
43
- ]
44
- # 4xx
45
- case code
46
- when 400
47
- @errors[0][:status] = "Bad Request"
48
- when 401
49
- @errors[0][:status] = "Unauthorized"
50
- when 403
51
- @errors[0][:status] = "Forbidden"
52
- when 404
53
- @errors[0][:status] = "Not Found"
54
- when 405
55
- @errors[0][:status] = "Method Not Allowed"
56
- when 406
57
- @errors[0][:status] = "Not Acceptable"
58
- when 408
59
- @errors[0][:status] = "Request Timeout"
60
- # 5xx
61
- when 501
62
- @errors[0][:status] = "Not Implemented"
63
- else
64
- # other
65
- @errors[0][:status] = "Internal Server Error"
66
- end
67
- @errors[0][:status] = "#{code} #{@errors[0][:status]}"
68
- if nil != internal
69
- @errors[0][:meta] = { :'internal-error' => internal }
27
+ if nil != internal
28
+ body[:meta] = {
29
+ 'internal-error' => internal
30
+ }
31
+ end
32
+ super(status_code: status, content_type: 'application/vnd.api+json;charset=utf-8', body: body)
70
33
  end
71
- end
72
-
73
- def code ()
74
- return @errors[0][:code]
75
- end
76
34
 
77
- def content_type ()
78
- "application/vnd.api+json;charset=utf-8"
79
- end
35
+ def code
36
+ @body[:errors][0][:code]
37
+ end
80
38
 
81
- def body ()
82
- {
83
- :errors => @errors
84
- }
85
- end
39
+ def message
40
+ @body[:errors][0][:detail]
41
+ end
86
42
 
87
- def content_type_and_body ()
88
- [ content_type(), body() ]
89
- end
43
+ def content_type_and_body
44
+ [ 'application/vnd.api+json', message ]
45
+ end
90
46
 
91
- end
47
+ end # class Error
92
48
 
49
+ end # JSONAPI module
93
50
  end # Job module
94
51
  end # SP module