tzispa 0.6.1 → 0.7.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 +4 -4
- data/CHANGELOG.md +12 -0
- data/lib/tzispa/api/handler.rb +54 -23
- data/lib/tzispa/app.rb +60 -68
- data/lib/tzispa/cli.rb +42 -3
- data/lib/tzispa/commands/api.rb +55 -0
- data/lib/tzispa/commands/app.rb +83 -0
- data/lib/tzispa/commands/cli/generate.rb +60 -0
- data/lib/tzispa/commands/command.rb +28 -0
- data/lib/tzispa/commands/console.rb +62 -0
- data/lib/tzispa/commands/helpers/i18n.rb +67 -0
- data/lib/tzispa/commands/helpers/project.rb +69 -0
- data/lib/tzispa/commands/helpers/repository.rb +46 -0
- data/lib/tzispa/commands/project.rb +104 -0
- data/lib/tzispa/commands/repository.rb +66 -0
- data/lib/tzispa/commands/rig.rb +28 -0
- data/lib/tzispa/commands/server.rb +26 -0
- data/lib/tzispa/config/{appconfig.rb → app_config.rb} +12 -32
- data/lib/tzispa/config/base.rb +7 -5
- data/lib/tzispa/config/db_config.rb +67 -0
- data/lib/tzispa/config/yaml.rb +9 -10
- data/lib/tzispa/context.rb +3 -2
- data/lib/tzispa/controller/api.rb +66 -60
- data/lib/tzispa/controller/auth_layout.rb +4 -28
- data/lib/tzispa/controller/base.rb +61 -24
- data/lib/tzispa/controller/exceptions.rb +3 -4
- data/lib/tzispa/controller/http_error.rb +0 -3
- data/lib/tzispa/controller/layout.rb +4 -4
- data/lib/tzispa/domain.rb +27 -23
- data/lib/tzispa/env.rb +34 -0
- data/lib/tzispa/environment.rb +231 -0
- data/lib/tzispa/http/context.rb +65 -80
- data/lib/tzispa/http/request.rb +29 -17
- data/lib/tzispa/http/response.rb +45 -12
- data/lib/tzispa/route_set.rb +100 -0
- data/lib/tzispa/server.rb +61 -0
- data/lib/tzispa/tzisparc.rb +80 -0
- data/lib/tzispa/version.rb +1 -1
- data/lib/tzispa.rb +3 -1
- data/tzispa.gemspec +12 -6
- metadata +68 -17
- data/lib/tzispa/command/api.rb +0 -24
- data/lib/tzispa/command/app.rb +0 -95
- data/lib/tzispa/command/cli/generate.rb +0 -51
- data/lib/tzispa/command/project.rb +0 -258
- data/lib/tzispa/command/rig.rb +0 -26
- data/lib/tzispa/controller/signed_api.rb +0 -13
- data/lib/tzispa/http/session_flash_bag.rb +0 -62
- data/lib/tzispa/middleware.rb +0 -48
- data/lib/tzispa/routes.rb +0 -69
@@ -7,114 +7,120 @@ require 'tzispa/controller/exceptions'
|
|
7
7
|
require 'tzispa/helpers/response'
|
8
8
|
require 'tzispa/utils/string'
|
9
9
|
|
10
|
-
|
11
10
|
module Tzispa
|
12
11
|
module Controller
|
13
12
|
|
14
13
|
class ControllerException < StandardError; end
|
15
14
|
|
16
15
|
class Api < Base
|
17
|
-
|
18
|
-
using Tzispa::Utils
|
16
|
+
using Tzispa::Utils::TzString
|
19
17
|
|
20
18
|
include Tzispa::Helpers::Response
|
21
19
|
|
22
20
|
def dispatch!
|
23
|
-
handler_name, domain_name = context.router_params[:handler].split('.').reverse
|
24
|
-
domain = domain_name.nil? ? context.app.domain : Tzispa::Domain.new(name: domain_name)
|
25
21
|
verb = context.router_params[:verb]
|
26
22
|
predicate = context.router_params[:predicate]
|
27
|
-
handler =
|
23
|
+
handler = prepare_handler
|
28
24
|
handler.run! verb, predicate
|
29
|
-
send(handler.
|
25
|
+
send(handler.type, handler) if handler.type
|
30
26
|
response.finish
|
31
27
|
end
|
32
28
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
29
|
+
def prepare_handler
|
30
|
+
self.class.handler_class(request_method, domain, handler_name).new(context)
|
31
|
+
end
|
32
|
+
|
33
|
+
def domain
|
34
|
+
_, domain_name = context.router_params[:handler].split('.').reverse
|
35
|
+
domain_name ? Tzispa::Domain.new(name: domain_name) : context.app.domain
|
36
|
+
end
|
37
|
+
|
38
|
+
def handler_name
|
39
|
+
context.router_params[:handler].split('.').last
|
40
|
+
end
|
41
|
+
|
42
|
+
def handler_redirect_url(url)
|
43
|
+
if url && !url.strip.empty?
|
44
|
+
url.start_with?('#') ? "#{request.referer}#{url}" : url
|
36
45
|
else
|
37
46
|
request.referer
|
38
|
-
end
|
39
|
-
|
40
|
-
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def redirect(handler)
|
51
|
+
api_flash(handler.message) if handler.error?
|
52
|
+
context.redirect handler.redirect_url(handler.data), config.absolute_redirects, response
|
41
53
|
end
|
42
54
|
|
43
55
|
def html(handler)
|
44
|
-
|
45
|
-
|
46
|
-
response.body << handler.data
|
47
|
-
set_api_headers handler.status
|
56
|
+
content = handler.error? ? handler.message : handler.data
|
57
|
+
api_response :htm, content, handler.status, handler.error
|
48
58
|
end
|
49
59
|
|
50
60
|
def json(handler)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
set_api_headers handler.status
|
61
|
+
content = if handler.error?
|
62
|
+
{ error_message: handler.message,
|
63
|
+
error_code: handler.error }.to_json
|
64
|
+
else
|
65
|
+
handler.data.is_a?(::String) ? JSON.parse(handler.data) : handler.data.to_json
|
66
|
+
end
|
67
|
+
api_response :json, content, handler.status, handler.error
|
59
68
|
end
|
60
69
|
|
61
70
|
def text(handler)
|
62
|
-
|
63
|
-
|
64
|
-
response.body << handler.data
|
65
|
-
set_api_headers handler.status
|
71
|
+
content = handler.error? ? handler.message : handler.data
|
72
|
+
api_response :text, content, handler.status, handler.error
|
66
73
|
end
|
67
74
|
|
68
75
|
def download(handler)
|
69
76
|
send_file handler.data[:path], handler.data
|
70
77
|
end
|
71
78
|
|
72
|
-
|
79
|
+
def api_flash(message)
|
80
|
+
context.flash << message if config.sessions&.enabled
|
81
|
+
end
|
82
|
+
|
83
|
+
def api_response(type, content, status = nil, error = nil)
|
84
|
+
content_type type
|
85
|
+
response.body << content
|
86
|
+
response.status = status if status
|
87
|
+
api_headers error
|
88
|
+
end
|
73
89
|
|
90
|
+
def request_method
|
91
|
+
context.request_method.downcase
|
92
|
+
end
|
93
|
+
|
94
|
+
class << self
|
74
95
|
def handler_class_name(handler_name)
|
75
96
|
"#{handler_name.camelize}Handler"
|
76
97
|
end
|
77
98
|
|
78
|
-
def handler_class_file(domain, handler_name)
|
79
|
-
"#{domain.path}/api/#{handler_name}.rb"
|
99
|
+
def handler_class_file(domain, handler_name, request_method)
|
100
|
+
"#{domain.path}/api/#{request_method}/#{handler_name}.rb"
|
80
101
|
end
|
81
102
|
|
82
|
-
def handler_namespace(domain)
|
83
|
-
"#{domain.name.to_s.camelize}::Api"
|
103
|
+
def handler_namespace(domain, request_method)
|
104
|
+
"#{domain.name.to_s.camelize}::Api::#{request_method.capitalize}"
|
84
105
|
end
|
85
106
|
|
86
|
-
def handler_class(domain, handler_name)
|
87
|
-
domain.require "api/#{handler_name}"
|
88
|
-
"#{handler_namespace domain}::#{handler_class_name handler_name}"
|
107
|
+
def handler_class(request_method, domain, handler_name)
|
108
|
+
domain.require "api/#{request_method}/#{handler_name}"
|
109
|
+
"#{handler_namespace domain, request_method}::#{handler_class_name handler_name}"
|
110
|
+
.constantize
|
89
111
|
end
|
90
|
-
|
91
|
-
def generate_handler(domain, name)
|
92
|
-
raise "The handler '#{name}' already exist" if File.exist?(handler_class_file)
|
93
|
-
File.open(handler_class_file(domain, name), "w") { |f|
|
94
|
-
handler_code = String.new
|
95
|
-
f.puts handler_code.indenter("require 'tzispa/api/handler'\n\n")
|
96
|
-
level = 0
|
97
|
-
handler_namespace.split('::').each { |ns|
|
98
|
-
f.puts handler_code.indenter("module #{ns}\n", level > 0 ? 2 : 0).to_s
|
99
|
-
level += 1
|
100
|
-
}
|
101
|
-
f.puts handler_code.indenter("\nclass #{handler_class_name} < Tzispa::Api::Handler\n\n", 2)
|
102
|
-
f.puts handler_code.indenter("end\n\n")
|
103
|
-
handler_namespace.split('::').each { |ns|
|
104
|
-
f.puts handler_code.unindenter("end\n", 2)
|
105
|
-
}
|
106
|
-
}
|
107
|
-
end
|
108
|
-
|
109
112
|
end
|
110
113
|
|
111
114
|
private
|
112
115
|
|
113
|
-
def
|
114
|
-
|
115
|
-
|
116
|
+
def api_headers(error = nil)
|
117
|
+
handler = context.router_params[:handler]
|
118
|
+
verb = context.router_params[:verb]
|
119
|
+
predicate = context.router_params[:predicate]
|
120
|
+
response['X-API'] = "#{handler}:#{verb}:#{predicate}"
|
121
|
+
response['X-API-SR'] = error.to_s if error
|
116
122
|
end
|
117
|
-
|
118
123
|
end
|
124
|
+
|
119
125
|
end
|
120
126
|
end
|
@@ -1,37 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
require 'tzispa/controller/base'
|
5
|
-
require 'tzispa/controller/exceptions'
|
6
|
-
require 'tzispa/helpers/response'
|
7
|
-
require 'tzispa_rig'
|
3
|
+
require 'tzispa/controller/layout'
|
8
4
|
|
9
5
|
module Tzispa
|
10
6
|
module Controller
|
11
|
-
class AuthLayout < Base
|
12
|
-
include Tzispa::Helpers::Response
|
13
|
-
|
14
|
-
def render!
|
15
|
-
if (layout_name == login_layout) || context.logged?
|
16
|
-
rig = Tzispa::Rig::Engine.layout name: layout_name, domain: application.domain, content_type: context.router_params[:format] || config.default_format
|
17
|
-
response.body << rig.render(context)
|
18
|
-
content_type rig.content_type
|
19
|
-
else
|
20
|
-
context.redirect login_layout, true, response
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def layout_name
|
27
|
-
context.layout || config.default_layout
|
28
|
-
end
|
29
|
-
|
30
|
-
def login_layout
|
31
|
-
config.login_layout
|
32
|
-
end
|
33
|
-
|
34
7
|
|
8
|
+
class AuthLayout < Layout
|
9
|
+
before :login_redirect
|
35
10
|
end
|
11
|
+
|
36
12
|
end
|
37
13
|
end
|
@@ -2,7 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'forwardable'
|
4
4
|
require 'tzispa/helpers/error_view'
|
5
|
-
|
5
|
+
require 'tzispa/http/context'
|
6
|
+
require 'tzispa/environment'
|
6
7
|
|
7
8
|
module Tzispa
|
8
9
|
module Controller
|
@@ -12,48 +13,84 @@ module Tzispa
|
|
12
13
|
|
13
14
|
include Tzispa::Helpers::ErrorView
|
14
15
|
|
15
|
-
attr_reader :context, :application
|
16
|
-
def_delegators :@context, :request, :response, :config
|
16
|
+
attr_reader :context, :application, :callmethod
|
17
|
+
def_delegators :@context, :request, :response, :config,
|
18
|
+
:login_redirect, :unauthorized_but_logged
|
17
19
|
|
18
|
-
def initialize(app, callmethod=nil)
|
20
|
+
def initialize(app, callmethod = nil)
|
19
21
|
@callmethod = callmethod
|
20
22
|
@application = app
|
21
23
|
end
|
22
24
|
|
23
25
|
def call(env)
|
24
26
|
@context = Tzispa::Http::Context.new(@application, env)
|
25
|
-
|
26
|
-
#@context = env[Tzispa::ENV_TZISPA_CONTEXT]
|
27
|
-
invoke @callmethod if @callmethod
|
27
|
+
invoke if callmethod
|
28
28
|
response.finish
|
29
29
|
end
|
30
30
|
|
31
|
+
class << self
|
32
|
+
def before(*args)
|
33
|
+
(@before_chain ||= []).tap do |bef|
|
34
|
+
args&.each do |s|
|
35
|
+
s = s.to_sym
|
36
|
+
bef << s unless bef.include?(s)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
31
42
|
private
|
32
43
|
|
33
|
-
def invoke
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
send "#{@callmethod}"
|
38
|
-
rescue Tzispa::Rig::NotFound => ex
|
39
|
-
context.logger.info "#{ex.message} (#{ex.class})"
|
40
|
-
404
|
41
|
-
rescue StandardError, ScriptError => ex
|
42
|
-
context.logger.error "#{ex.message} (#{ex.class}):\n #{ex.backtrace.join("\n\t") if ex.respond_to?(:backtrace) && ex.backtrace}"
|
43
|
-
debug_info = debug_info(ex) if config.developing
|
44
|
-
500
|
45
|
-
end
|
44
|
+
def invoke
|
45
|
+
prepare_response catch(:halt) {
|
46
|
+
do_before
|
47
|
+
send callmethod
|
46
48
|
}
|
49
|
+
rescue Tzispa::Rig::NotFound => ex
|
50
|
+
prepare_client_error(404, ex)
|
51
|
+
rescue StandardError, ScriptError, SecurityError => ex
|
52
|
+
prepare_server_error(500, ex)
|
53
|
+
end
|
54
|
+
|
55
|
+
def prepare_response(status, content = nil)
|
47
56
|
response.status = status if status.is_a?(Integer)
|
48
57
|
if response.client_error?
|
49
|
-
|
58
|
+
prepare_client_error(status)
|
50
59
|
elsif response.server_error?
|
51
|
-
|
52
|
-
|
53
|
-
|
60
|
+
prepare_server_error(status)
|
61
|
+
elsif content
|
62
|
+
response.body = content
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def do_before
|
67
|
+
self.class.before.each { |hook| send hook }
|
68
|
+
end
|
69
|
+
|
70
|
+
def prepare_client_error(status, error = nil)
|
71
|
+
status.tap do |code|
|
72
|
+
context.logger.info log_format(code, error.to_s) if error
|
73
|
+
response.body = error_page(context.domain, status: code)
|
54
74
|
end
|
55
75
|
end
|
56
76
|
|
77
|
+
def prepare_server_error(status, error = nil)
|
78
|
+
status.tap do |code|
|
79
|
+
context.logger.error log_format(code, error_log(error)) if error
|
80
|
+
response.body = if error && Tzispa::Environment.development?
|
81
|
+
debug_info(error)
|
82
|
+
else
|
83
|
+
error_page(context.domain, status: code)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def log_format(status, msg)
|
89
|
+
String.new.tap do |str|
|
90
|
+
str << "[#{context.request.ip} #{DateTime.now}] #{context.request.request_method}"
|
91
|
+
str << " #{context.request.fullpath} #{status}\n#{msg}"
|
92
|
+
end
|
93
|
+
end
|
57
94
|
end
|
58
95
|
|
59
96
|
end
|
@@ -2,10 +2,9 @@ module Tzispa
|
|
2
2
|
module Controller
|
3
3
|
module Error
|
4
4
|
|
5
|
-
class ControllerError < StandardError; end
|
6
|
-
class Http < ControllerError; end
|
7
|
-
class
|
8
|
-
class InvalidSign < ControllerError; end;
|
5
|
+
class ControllerError < StandardError; end
|
6
|
+
class Http < ControllerError; end
|
7
|
+
class InvalidSign < ControllerError; end
|
9
8
|
|
10
9
|
end
|
11
10
|
end
|
@@ -4,7 +4,6 @@ require 'tzispa_rig'
|
|
4
4
|
require 'tzispa/controller/base'
|
5
5
|
require 'tzispa/controller/exceptions'
|
6
6
|
require 'tzispa/helpers/response'
|
7
|
-
require 'tzispa_rig'
|
8
7
|
|
9
8
|
module Tzispa
|
10
9
|
module Controller
|
@@ -12,7 +11,9 @@ module Tzispa
|
|
12
11
|
include Tzispa::Helpers::Response
|
13
12
|
|
14
13
|
def render!
|
15
|
-
rig = Tzispa::Rig::Engine.layout name: layout_name,
|
14
|
+
rig = Tzispa::Rig::Engine.layout name: layout_name,
|
15
|
+
domain: application.domain,
|
16
|
+
content_type: context.router_params[:format] || config.default_format
|
16
17
|
response.body << rig.render(context)
|
17
18
|
content_type rig.content_type
|
18
19
|
end
|
@@ -22,8 +23,7 @@ module Tzispa
|
|
22
23
|
def layout_name
|
23
24
|
context.layout || config.default_layout
|
24
25
|
end
|
25
|
-
|
26
|
-
|
27
26
|
end
|
27
|
+
|
28
28
|
end
|
29
29
|
end
|
data/lib/tzispa/domain.rb
CHANGED
@@ -3,47 +3,52 @@
|
|
3
3
|
require 'tzispa/utils/string'
|
4
4
|
|
5
5
|
module Tzispa
|
6
|
-
class Domain
|
7
6
|
|
8
|
-
|
7
|
+
class Domain
|
8
|
+
using Tzispa::Utils::TzString
|
9
9
|
|
10
10
|
attr_reader :name, :root
|
11
11
|
|
12
|
-
|
13
|
-
DEFAULT_DOMAINS_ROOT = :apps
|
14
|
-
|
15
|
-
|
16
|
-
def initialize(name=DEFAULT_DOMAIN_NAME, root=DEFAULT_DOMAINS_ROOT)
|
12
|
+
def initialize(name)
|
17
13
|
@name = name
|
18
|
-
@root = root
|
14
|
+
@root = "#{Tzispa::Environment.instance.root}/#{Tzispa::Environment.instance.apps_path}"
|
15
|
+
instance_eval "module ::#{name.to_s.capitalize}; end"
|
16
|
+
end
|
17
|
+
|
18
|
+
def setup
|
19
|
+
require_dir
|
20
|
+
require_dir 'helpers'
|
21
|
+
require_dir 'services'
|
22
|
+
require_dir 'api'
|
23
|
+
require_dir 'middleware'
|
19
24
|
end
|
20
25
|
|
21
26
|
def path
|
22
|
-
|
27
|
+
@path ||= root % name.to_s.downcase
|
23
28
|
end
|
24
29
|
|
25
30
|
def require(file)
|
26
|
-
Kernel.require "
|
31
|
+
Kernel.require "#{path}/#{file}"
|
27
32
|
end
|
28
33
|
|
29
34
|
def load(file)
|
30
|
-
Kernel.load "
|
35
|
+
Kernel.load "#{path}/#{file}.rb"
|
31
36
|
end
|
32
37
|
|
33
38
|
def require_dir(dir = nil)
|
34
|
-
rqpath = dir ? "
|
35
|
-
Dir["
|
39
|
+
rqpath = dir ? "#{path}/#{dir}" : path.to_s
|
40
|
+
Dir["#{rqpath}/*.rb"].each do |file|
|
36
41
|
name = file.split('/').last.split('.').first
|
37
|
-
Kernel.require "
|
38
|
-
|
42
|
+
Kernel.require "#{rqpath}/#{name}"
|
43
|
+
end
|
39
44
|
end
|
40
45
|
|
41
46
|
def load_dir(dir = nil)
|
42
|
-
rqpath = dir ? "
|
43
|
-
Dir["
|
47
|
+
rqpath = dir ? "#{path}/#{dir}" : path.to_s
|
48
|
+
Dir["#{rqpath}/*.rb"].each do |file|
|
44
49
|
name = file.split('/').last
|
45
|
-
Kernel.load "
|
46
|
-
|
50
|
+
Kernel.load "#{rqpath}/#{name}"
|
51
|
+
end
|
47
52
|
end
|
48
53
|
|
49
54
|
def include(cmod)
|
@@ -51,13 +56,12 @@ module Tzispa
|
|
51
56
|
end
|
52
57
|
|
53
58
|
def self.require(domain, file)
|
54
|
-
|
59
|
+
new(name: domain).require(file)
|
55
60
|
end
|
56
61
|
|
57
62
|
def self.load(domain, file)
|
58
|
-
|
63
|
+
new(name: domain).load(file)
|
59
64
|
end
|
60
|
-
|
61
|
-
|
62
65
|
end
|
66
|
+
|
63
67
|
end
|
data/lib/tzispa/env.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dotenv'
|
4
|
+
|
5
|
+
module Tzispa
|
6
|
+
|
7
|
+
class Env
|
8
|
+
def initialize(env: ENV)
|
9
|
+
@env = env
|
10
|
+
end
|
11
|
+
|
12
|
+
def [](key)
|
13
|
+
@env[key]
|
14
|
+
end
|
15
|
+
|
16
|
+
def []=(key, value)
|
17
|
+
@env[key] = value
|
18
|
+
end
|
19
|
+
|
20
|
+
def load!(path)
|
21
|
+
return unless defined?(Dotenv)
|
22
|
+
|
23
|
+
contents = ::File.open(path, 'rb:bom|utf-8', &:read)
|
24
|
+
parsed = Dotenv::Parser.call(contents)
|
25
|
+
|
26
|
+
parsed.each do |k, v|
|
27
|
+
next if @env.key?(k)
|
28
|
+
@env[k] = v
|
29
|
+
end
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|