gloo-web 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.
- checksums.yaml +7 -0
- data/lib/gloo-web.rb +48 -0
- data/lib/objs/element.rb +252 -0
- data/lib/objs/field.rb +428 -0
- data/lib/objs/form.rb +269 -0
- data/lib/objs/page.rb +560 -0
- data/lib/objs/partial.rb +208 -0
- data/lib/objs/svr.rb +711 -0
- data/lib/routing/resource_router.rb +43 -0
- data/lib/routing/router.rb +228 -0
- data/lib/routing/show_routes.rb +90 -0
- data/lib/web_svr/asset.rb +405 -0
- data/lib/web_svr/asset_info.rb +114 -0
- data/lib/web_svr/config.rb +55 -0
- data/lib/web_svr/embedded_renderer.rb +152 -0
- data/lib/web_svr/handler.rb +152 -0
- data/lib/web_svr/request.rb +141 -0
- data/lib/web_svr/request_params.rb +179 -0
- data/lib/web_svr/response.rb +175 -0
- data/lib/web_svr/response_code.rb +67 -0
- data/lib/web_svr/server.rb +102 -0
- data/lib/web_svr/session.rb +213 -0
- data/lib/web_svr/table_renderer.rb +149 -0
- data/lib/web_svr/web_method.rb +52 -0
- metadata +81 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2024 Eric Crane. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# The Response for a web Request.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
module WebSvr
|
|
8
|
+
class Response
|
|
9
|
+
|
|
10
|
+
#
|
|
11
|
+
# SEE: https://stackoverflow.com/questions/23714383/what-are-all-the-possible-values-for-http-content-type-header#48704300
|
|
12
|
+
# for a list of content types.
|
|
13
|
+
#
|
|
14
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
|
15
|
+
TEXT_TYPE = 'text/plain'.freeze
|
|
16
|
+
JSON_TYPE = 'application/json'.freeze
|
|
17
|
+
HTML_TYPE = 'text/html'.freeze
|
|
18
|
+
|
|
19
|
+
attr_reader :code, :type, :data
|
|
20
|
+
attr_accessor :location
|
|
21
|
+
attr_accessor :file_name
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# ---------------------------------------------------------------------
|
|
25
|
+
# Initialization
|
|
26
|
+
# ---------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
#
|
|
29
|
+
# Set up the web server.
|
|
30
|
+
#
|
|
31
|
+
def initialize( engine = nil,
|
|
32
|
+
code = WebSvr::ResponseCode::SUCCESS,
|
|
33
|
+
type = HTML_TYPE,
|
|
34
|
+
data = nil,
|
|
35
|
+
assetCache = false,
|
|
36
|
+
file_name = nil,
|
|
37
|
+
download = false )
|
|
38
|
+
|
|
39
|
+
@engine = engine
|
|
40
|
+
@log = @engine.log if @engine
|
|
41
|
+
|
|
42
|
+
@code = code
|
|
43
|
+
@type = type
|
|
44
|
+
@data = data
|
|
45
|
+
@assetCache = assetCache
|
|
46
|
+
@location = nil
|
|
47
|
+
@file_name = file_name
|
|
48
|
+
@download = download
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# ---------------------------------------------------------------------
|
|
53
|
+
# Static Helper Functions
|
|
54
|
+
# ---------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
#
|
|
57
|
+
# Helper to create a successful JSON response with the given data.
|
|
58
|
+
#
|
|
59
|
+
def self.json_response( engine, data,
|
|
60
|
+
code = WebSvr::ResponseCode::SUCCESS )
|
|
61
|
+
|
|
62
|
+
return WebSvr::Response.new( engine, code, JSON_TYPE, data )
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
#
|
|
66
|
+
# Helper to create a successful text response with the given data.
|
|
67
|
+
#
|
|
68
|
+
def self.text_response( engine, data,
|
|
69
|
+
code = WebSvr::ResponseCode::SUCCESS )
|
|
70
|
+
|
|
71
|
+
return WebSvr::Response.new( engine, code, TEXT_TYPE, data )
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
#
|
|
75
|
+
# Helper to create a successful web response with the given data.
|
|
76
|
+
#
|
|
77
|
+
def self.html_response( engine, data,
|
|
78
|
+
code = WebSvr::ResponseCode::SUCCESS )
|
|
79
|
+
|
|
80
|
+
return WebSvr::Response.new( engine, code, HTML_TYPE, data )
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
#
|
|
84
|
+
# Helper to create a redirect response.
|
|
85
|
+
#
|
|
86
|
+
def self.redirect_response( engine, target )
|
|
87
|
+
code = WebSvr::ResponseCode::FOUND
|
|
88
|
+
data = <<~TEXT
|
|
89
|
+
<head>
|
|
90
|
+
<html>
|
|
91
|
+
<body><a href="#{target}">target is here</a></body>
|
|
92
|
+
</html>
|
|
93
|
+
</head>
|
|
94
|
+
TEXT
|
|
95
|
+
|
|
96
|
+
response = WebSvr::Response.new( engine, code, HTML_TYPE, data )
|
|
97
|
+
response.location = target
|
|
98
|
+
|
|
99
|
+
return response
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# ---------------------------------------------------------------------
|
|
104
|
+
# Data Functions
|
|
105
|
+
# ---------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
#
|
|
108
|
+
# Add content to the payload.
|
|
109
|
+
#
|
|
110
|
+
def add content
|
|
111
|
+
@data = '' if @data.nil?
|
|
112
|
+
@data << content
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
#
|
|
116
|
+
# Get the headers for the response.
|
|
117
|
+
#
|
|
118
|
+
def headers
|
|
119
|
+
#
|
|
120
|
+
# TO DO: Add more cookie headers here.
|
|
121
|
+
#
|
|
122
|
+
# https://stackoverflow.com/questions/3295083/how-do-i-set-a-cookie-with-a-ruby-rack-middleware-component
|
|
123
|
+
# https://www.rubydoc.info/gems/rack/1.4.7/Rack/Session/Cookie
|
|
124
|
+
#
|
|
125
|
+
|
|
126
|
+
headers = { CONTENT_TYPE => @type }
|
|
127
|
+
|
|
128
|
+
if @location
|
|
129
|
+
headers[ 'Location' ] = @location
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
if @assetCache || @file_name
|
|
133
|
+
headers[ 'Cache-Control' ] = 'public, max-age=604800'
|
|
134
|
+
headers[ 'Expires' ] = (Time.now.utc + 604800).to_s
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
if @file_name
|
|
138
|
+
disp = @download ? 'attachment' : 'inline'
|
|
139
|
+
headers[ 'Content-Disposition' ] = "#{disp}; filename=#{@file_name}"
|
|
140
|
+
headers[ 'Content-Length' ] = @data.length.to_s
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
session = @engine&.running_app&.obj&.session
|
|
144
|
+
headers = session.add_session_for_response( headers ) if session
|
|
145
|
+
|
|
146
|
+
# Clear out session data after the response is prepared.
|
|
147
|
+
@engine&.running_app&.obj&.reset_session_data
|
|
148
|
+
|
|
149
|
+
return headers
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
#
|
|
153
|
+
# Get the final result that will be returned as the
|
|
154
|
+
# response to the web request.
|
|
155
|
+
#
|
|
156
|
+
def result
|
|
157
|
+
return [ @code, headers, @data ]
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
# ---------------------------------------------------------------------
|
|
162
|
+
# Helper functions
|
|
163
|
+
# ---------------------------------------------------------------------
|
|
164
|
+
|
|
165
|
+
#
|
|
166
|
+
# Write the result information to the log.
|
|
167
|
+
#
|
|
168
|
+
def log
|
|
169
|
+
return unless @log
|
|
170
|
+
|
|
171
|
+
@log.info "Response #{@code} #{@type}"
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
end
|
|
175
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2024 Eric Crane. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# Standard Response Codes.
|
|
5
|
+
#
|
|
6
|
+
# See:
|
|
7
|
+
# https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
|
|
8
|
+
# https://www.geeksforgeeks.org/10-most-common-http-status-codes/
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
module WebSvr
|
|
12
|
+
class ResponseCode
|
|
13
|
+
|
|
14
|
+
# WebSvr::ResponseCode::SUCCESS
|
|
15
|
+
SUCCESS = 200.freeze
|
|
16
|
+
CODE_200 = 'Success/OK'.freeze
|
|
17
|
+
|
|
18
|
+
CREATED = 201.freeze
|
|
19
|
+
CODE_201 = 'Created'.freeze
|
|
20
|
+
|
|
21
|
+
ACCEPTED = 202.freeze
|
|
22
|
+
CODE_202 = 'Accepted'.freeze
|
|
23
|
+
|
|
24
|
+
NO_CONTENT = 204.freeze
|
|
25
|
+
CODE_204 = 'No Content'.freeze
|
|
26
|
+
|
|
27
|
+
PARTIAL_CONTENT = 206.freeze
|
|
28
|
+
CODE_206 = 'Partial Content'.freeze
|
|
29
|
+
|
|
30
|
+
MOVED_PERM = 301.freeze
|
|
31
|
+
CODE_301 = 'Moved Permanently'.freeze
|
|
32
|
+
|
|
33
|
+
FOUND = 302.freeze
|
|
34
|
+
CODE_302 = 'Found'.freeze
|
|
35
|
+
|
|
36
|
+
SEE_OTHER = 303.freeze
|
|
37
|
+
CODE_303 = 'See Other'.freeze
|
|
38
|
+
|
|
39
|
+
NOT_MODIFIED = 304.freeze
|
|
40
|
+
CODE_304 = 'Not Modified'.freeze
|
|
41
|
+
|
|
42
|
+
TEMP_REDIRECT = 307.freeze
|
|
43
|
+
CODE_307 = 'Temporary Redirect'.freeze
|
|
44
|
+
|
|
45
|
+
PERM_REDIRECT = 308.freeze
|
|
46
|
+
CODE_308 = 'Permanent Redirect'.freeze
|
|
47
|
+
|
|
48
|
+
BAD_REQUEST = 400.freeze
|
|
49
|
+
CODE_400 = 'Bad Request'.freeze
|
|
50
|
+
|
|
51
|
+
UNAUTHORIZED = 401.freeze
|
|
52
|
+
CODE_401 = 'Unauthorized'.freeze
|
|
53
|
+
|
|
54
|
+
FORBIDDEN = 403.freeze
|
|
55
|
+
CODE_403 = 'Forbidden'.freeze
|
|
56
|
+
|
|
57
|
+
NOT_FOUND = 404.freeze
|
|
58
|
+
CODE_404 = 'Not Found'.freeze
|
|
59
|
+
|
|
60
|
+
SERVER_ERR = 500.freeze
|
|
61
|
+
CODE_500 = 'Internal Server Error'.freeze
|
|
62
|
+
|
|
63
|
+
NOT_IMPLEMENTED = 501.freeze
|
|
64
|
+
CODE_501 = 'Not Implemented'.freeze
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2024 Eric Crane. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# Starting work on web server inside gloo.
|
|
5
|
+
#
|
|
6
|
+
# UNDER CONSTRUCTION!
|
|
7
|
+
#
|
|
8
|
+
# Simple tests:
|
|
9
|
+
# > curl http://localhost:8087/test/
|
|
10
|
+
# > curl http://localhost:8087/web/
|
|
11
|
+
# > curl http://localhost:8087/test/1
|
|
12
|
+
# > curl http://localhost:8087/test?param=123
|
|
13
|
+
#
|
|
14
|
+
# Run in loop:
|
|
15
|
+
# for i in {1..99}; do curl http://localhost:8087/; done
|
|
16
|
+
#
|
|
17
|
+
# Links:
|
|
18
|
+
# https://github.com/rack/rack
|
|
19
|
+
# https://github.com/rack/rack/blob/main/lib/rack/builder.rb
|
|
20
|
+
# https://thoughtbot.com/blog/ruby-rack-tutorial
|
|
21
|
+
# https://www.rubydoc.info/gems/rack/1.5.5/Rack/Runtime
|
|
22
|
+
#
|
|
23
|
+
|
|
24
|
+
require 'rack'
|
|
25
|
+
|
|
26
|
+
module WebSvr
|
|
27
|
+
class Server
|
|
28
|
+
|
|
29
|
+
# ---------------------------------------------------------------------
|
|
30
|
+
# Initialization
|
|
31
|
+
# ---------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
#
|
|
34
|
+
# Set up the web server.
|
|
35
|
+
#
|
|
36
|
+
def initialize( engine, handler, config = nil, ssl_config = nil )
|
|
37
|
+
@config = config ? config : WebSvr::Config.new
|
|
38
|
+
@ssl_config = ssl_config
|
|
39
|
+
@engine = engine
|
|
40
|
+
@log = @engine.log
|
|
41
|
+
@handler = handler
|
|
42
|
+
|
|
43
|
+
@log.debug 'Gloo web server intialized…'
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# ---------------------------------------------------------------------
|
|
48
|
+
# Start and Stop the server.
|
|
49
|
+
# ---------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
#
|
|
52
|
+
# Start the web server.
|
|
53
|
+
#
|
|
54
|
+
def start
|
|
55
|
+
opts = {
|
|
56
|
+
:Port => @config.port,
|
|
57
|
+
:Host => @config.host
|
|
58
|
+
}
|
|
59
|
+
Thread.abort_on_exception = true
|
|
60
|
+
@server_thread = Thread.new {
|
|
61
|
+
Rack::Handler::Thin.run( self, **options=opts ) do |server|
|
|
62
|
+
if @ssl_config
|
|
63
|
+
server.ssl = true
|
|
64
|
+
server.ssl_options = @ssl_config
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
}
|
|
68
|
+
@log.debug 'Web server has started.'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
#
|
|
72
|
+
# Stop the web server
|
|
73
|
+
#
|
|
74
|
+
def stop
|
|
75
|
+
@log.debug 'Stopping the web server…'
|
|
76
|
+
|
|
77
|
+
@server_thread.kill
|
|
78
|
+
|
|
79
|
+
@log.debug 'The web server has been stopped.'
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# ---------------------------------------------------------------------
|
|
84
|
+
# Handle events
|
|
85
|
+
# ---------------------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
#
|
|
88
|
+
# Handle a request for a resource.
|
|
89
|
+
#
|
|
90
|
+
def call( env )
|
|
91
|
+
request = WebSvr::Request.new( @engine, @handler, env )
|
|
92
|
+
request.log
|
|
93
|
+
|
|
94
|
+
response = request.process
|
|
95
|
+
response.log if response
|
|
96
|
+
|
|
97
|
+
return response ? response.result : nil
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2024 Eric Crane. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# Helpers for getting and setting session data.
|
|
5
|
+
#
|
|
6
|
+
# Resources:
|
|
7
|
+
# https://www.rubydoc.info/gems/rack/1.5.5/Rack/Request#cookies-instance_method
|
|
8
|
+
# https://rubydoc.info/github/rack/rack/Rack/Utils#set_cookie_header-class_method
|
|
9
|
+
# https://en.wikipedia.org/wiki/HTTP_cookie
|
|
10
|
+
#
|
|
11
|
+
require 'base64'
|
|
12
|
+
|
|
13
|
+
module WebSvr
|
|
14
|
+
class Session
|
|
15
|
+
|
|
16
|
+
SESSION_CONTAINER = 'session'.freeze
|
|
17
|
+
SESSION_ID_NAME = 'session_id'.freeze
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# ---------------------------------------------------------------------
|
|
21
|
+
# Initialization
|
|
22
|
+
# ---------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
#
|
|
25
|
+
# Set up the web server.
|
|
26
|
+
#
|
|
27
|
+
def initialize( engine, server_obj )
|
|
28
|
+
@engine = engine
|
|
29
|
+
@log = @engine.log
|
|
30
|
+
|
|
31
|
+
@server_obj = server_obj
|
|
32
|
+
@include_in_response = false
|
|
33
|
+
@clearing_session = false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# ---------------------------------------------------------------------
|
|
38
|
+
# Set Session Data for Request
|
|
39
|
+
# ---------------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
#
|
|
42
|
+
# Get the session data from the encrypted cookie.
|
|
43
|
+
# Add it to the session container.
|
|
44
|
+
#
|
|
45
|
+
def set_session_data_for_request( env )
|
|
46
|
+
begin
|
|
47
|
+
cookie_hash = Rack::Utils.parse_cookies( env )
|
|
48
|
+
|
|
49
|
+
# Are we using sessions?
|
|
50
|
+
if @server_obj.use_session?
|
|
51
|
+
data = cookie_hash[ session_name ]
|
|
52
|
+
|
|
53
|
+
if data
|
|
54
|
+
data = decode_decrypt( data )
|
|
55
|
+
return unless data
|
|
56
|
+
|
|
57
|
+
@session_id = data[ SESSION_ID_NAME ]
|
|
58
|
+
|
|
59
|
+
data.each do |key, value|
|
|
60
|
+
unless key == SESSION_ID_NAME
|
|
61
|
+
@server_obj.set_session_var( key, value )
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
rescue => e
|
|
67
|
+
@engine.log_exception e
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# ---------------------------------------------------------------------
|
|
73
|
+
# Set Session Data for Response
|
|
74
|
+
# ---------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
#
|
|
77
|
+
# Temporarily set the flag to add the session data to the response.
|
|
78
|
+
# Once this is done, the flag will be cleared and it will not
|
|
79
|
+
# be added to the next request unless specifically set.
|
|
80
|
+
#
|
|
81
|
+
def add_session_to_response
|
|
82
|
+
@include_in_response = true
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def init_session_id
|
|
86
|
+
@session_id = Gloo::Objs::CsrfToken.generate_csrf_token
|
|
87
|
+
return @session_id
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
#
|
|
91
|
+
# Initialize the session id and add it to the data.
|
|
92
|
+
# Use the current session ID if it is there.
|
|
93
|
+
#
|
|
94
|
+
def get_session_id
|
|
95
|
+
if @clearing_session
|
|
96
|
+
@clearing_session = false
|
|
97
|
+
return nil
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
init_session_id if @session_id.blank?
|
|
101
|
+
|
|
102
|
+
return @session_id
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
#
|
|
106
|
+
# Clear out the session Id.
|
|
107
|
+
# Set the flag to add the session data to the response.
|
|
108
|
+
#
|
|
109
|
+
def clear_session_data
|
|
110
|
+
@session_id = nil
|
|
111
|
+
@clearing_session = true
|
|
112
|
+
add_session_to_response
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
#
|
|
116
|
+
# If there is session data, encrypt and add it to the response.
|
|
117
|
+
# Once done, clear out the session data.
|
|
118
|
+
#
|
|
119
|
+
def add_session_for_response( headers )
|
|
120
|
+
# Are we using sessions?
|
|
121
|
+
if @server_obj.use_session? && @include_in_response
|
|
122
|
+
# Reset the flag because we are adding to the session data now
|
|
123
|
+
@include_in_response = false
|
|
124
|
+
|
|
125
|
+
# Build and add encrypted session data
|
|
126
|
+
data = @server_obj.get_session_data
|
|
127
|
+
data[ SESSION_ID_NAME ] = get_session_id
|
|
128
|
+
|
|
129
|
+
unless data.empty?
|
|
130
|
+
data = encrypt_encode( data )
|
|
131
|
+
session_hash = {
|
|
132
|
+
value: data,
|
|
133
|
+
path: cookie_path,
|
|
134
|
+
expires: cookie_expires,
|
|
135
|
+
http_only: true }
|
|
136
|
+
|
|
137
|
+
if secure_cookie?
|
|
138
|
+
session_hash[ :secure ] = true
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
Rack::Utils.set_cookie_header!( headers, session_name, session_hash )
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
return headers
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
# ---------------------------------------------------------------------
|
|
150
|
+
# Helper functions
|
|
151
|
+
# ---------------------------------------------------------------------
|
|
152
|
+
|
|
153
|
+
#
|
|
154
|
+
# Encrypt and encode the session data.
|
|
155
|
+
#
|
|
156
|
+
def encrypt_encode( data )
|
|
157
|
+
return Gloo::Objs::Cipher.encrypt( data.to_json, key, iv )
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
#
|
|
161
|
+
# Decode and decrypt the session data.
|
|
162
|
+
#
|
|
163
|
+
def decode_decrypt( data )
|
|
164
|
+
return nil unless data && key && iv
|
|
165
|
+
|
|
166
|
+
data = Gloo::Objs::Cipher.decrypt( data, key, iv )
|
|
167
|
+
return JSON.parse( data )
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
#
|
|
171
|
+
# Get the session cookie name.
|
|
172
|
+
#
|
|
173
|
+
def session_name
|
|
174
|
+
return @server_obj.session_name
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
#
|
|
178
|
+
# Get the key for the encryption cipher.
|
|
179
|
+
#
|
|
180
|
+
def key
|
|
181
|
+
return @server_obj.encryption_key
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
#
|
|
185
|
+
# Get the initialization vector for the cipher.
|
|
186
|
+
#
|
|
187
|
+
def iv
|
|
188
|
+
return @server_obj.encryption_iv
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
#
|
|
192
|
+
# Get the path for the session cookie.
|
|
193
|
+
#
|
|
194
|
+
def cookie_path
|
|
195
|
+
return @server_obj.session_cookie_path
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
#
|
|
199
|
+
# Get the expiration time for the session cookie.
|
|
200
|
+
#
|
|
201
|
+
def cookie_expires
|
|
202
|
+
return @server_obj.session_cookie_expires
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
#
|
|
206
|
+
# Should the session cookie be secure?
|
|
207
|
+
#
|
|
208
|
+
def secure_cookie?
|
|
209
|
+
return @server_obj.session_cookie_secure
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
end
|
|
213
|
+
end
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2024 Eric Crane. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# A helper class used to render HTML tables.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
module WebSvr
|
|
8
|
+
class TableRenderer
|
|
9
|
+
|
|
10
|
+
TABLE = 'table'.freeze
|
|
11
|
+
THEAD = 'thead'.freeze
|
|
12
|
+
HEAD_CELL = 'head_cell'.freeze
|
|
13
|
+
ROW = 'row'.freeze
|
|
14
|
+
CELL = 'cell'.freeze
|
|
15
|
+
|
|
16
|
+
NO_DATA_FOUND = "<p>No data found.</p>".freeze
|
|
17
|
+
|
|
18
|
+
# ---------------------------------------------------------------------
|
|
19
|
+
# Initialization
|
|
20
|
+
# ---------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
# Set up the web server.
|
|
24
|
+
#
|
|
25
|
+
def initialize( engine )
|
|
26
|
+
@engine = engine
|
|
27
|
+
@log = @engine.log
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# ---------------------------------------------------------------------
|
|
32
|
+
# Container Renderer
|
|
33
|
+
# ---------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
#
|
|
36
|
+
# Render the query result set to an HTML table.
|
|
37
|
+
#
|
|
38
|
+
# params = {
|
|
39
|
+
# head: head,
|
|
40
|
+
# cols: result[0],
|
|
41
|
+
# rows: rows,
|
|
42
|
+
# styles: self.styles,
|
|
43
|
+
# cell_renderers: self.cell_renderers
|
|
44
|
+
# }
|
|
45
|
+
#
|
|
46
|
+
def data_to_table params
|
|
47
|
+
data = params[ :rows ]
|
|
48
|
+
return NO_DATA_FOUND if data.nil? || ( data.length == 0 )
|
|
49
|
+
|
|
50
|
+
single_row = true if ( data.length == 1 )
|
|
51
|
+
single_row = false if params[ :always_rows ]
|
|
52
|
+
|
|
53
|
+
if single_row
|
|
54
|
+
return data_to_single_row_table( params )
|
|
55
|
+
else
|
|
56
|
+
return data_to_table_rows( params )
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
#
|
|
61
|
+
# Show in single-row (form) format.
|
|
62
|
+
#
|
|
63
|
+
def data_to_single_row_table( params )
|
|
64
|
+
styles = params[ :styles ]
|
|
65
|
+
str = "<table class='#{styles[ TABLE ]}'> <tbody>"
|
|
66
|
+
row = params[ :rows ].first
|
|
67
|
+
|
|
68
|
+
params[ :columns ].each do |head|
|
|
69
|
+
next unless head[ :visible ]
|
|
70
|
+
cell = row[ head[ :data_index ] ]
|
|
71
|
+
|
|
72
|
+
if head[ :cell_renderer ]
|
|
73
|
+
cell_value = render_cell( row, head, params[ :columns ] )
|
|
74
|
+
else
|
|
75
|
+
cell_value = cell
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
str += "<tr class='#{styles[ ROW ]}'>"
|
|
79
|
+
str += "<th class='#{styles[ HEAD_CELL ]}'>#{head[ :title ]}</th>"
|
|
80
|
+
str += "<td class='#{styles[ CELL ]}'>#{cell_value}</td>"
|
|
81
|
+
str += "</tr>"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
str += "</tbody></table>"
|
|
85
|
+
return str
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
#
|
|
89
|
+
# Show in normal, multi-row format.
|
|
90
|
+
#
|
|
91
|
+
def data_to_table_rows( params )
|
|
92
|
+
styles = params[ :styles ]
|
|
93
|
+
# headers = params[ :head ]
|
|
94
|
+
|
|
95
|
+
str = "<table class='#{styles[ TABLE ]}'>"
|
|
96
|
+
str << "<thead class='#{styles[ THEAD ]}'><tr>"
|
|
97
|
+
|
|
98
|
+
params[ :columns ].each do |head|
|
|
99
|
+
next unless head[ :visible ]
|
|
100
|
+
str += "<th class='#{styles[ HEAD_CELL ]}'>#{head[ :title ]}</th>"
|
|
101
|
+
end
|
|
102
|
+
str << "</tr></thead><tbody>"
|
|
103
|
+
|
|
104
|
+
params[ :rows ].each do |row|
|
|
105
|
+
str += "<tr class='#{styles[ ROW ]}'>"
|
|
106
|
+
|
|
107
|
+
# row.each_with_index do |cell, i|
|
|
108
|
+
params[ :columns ].each do |head|
|
|
109
|
+
next unless head[ :visible ]
|
|
110
|
+
|
|
111
|
+
cell = row[ head[ :data_index ] ]
|
|
112
|
+
this_col_name = head[ :name ]
|
|
113
|
+
|
|
114
|
+
if head[ :cell_renderer ]
|
|
115
|
+
cell_value = render_cell( row, head, params[ :columns ] )
|
|
116
|
+
else
|
|
117
|
+
cell_value = cell
|
|
118
|
+
end
|
|
119
|
+
str += "<td class='#{styles[ CELL ]}'>#{cell_value}</td>"
|
|
120
|
+
end
|
|
121
|
+
str += "</tr>"
|
|
122
|
+
end
|
|
123
|
+
str += "</tbody></table>"
|
|
124
|
+
|
|
125
|
+
return str
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
#
|
|
129
|
+
# Render a cell using the cell renderer and the given
|
|
130
|
+
# context data (the row's values).
|
|
131
|
+
#
|
|
132
|
+
def render_cell row, col, cols
|
|
133
|
+
params = {}
|
|
134
|
+
|
|
135
|
+
cols.each_with_index do |c, i|
|
|
136
|
+
params[ c[ :name ] ] = row[ c[ :data_index ] ]
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
content = col[ :cell_renderer ]
|
|
140
|
+
content = @engine.running_app.obj.embedded_renderer.render content, params
|
|
141
|
+
|
|
142
|
+
# renderer = ERB.new( col[ :cell_renderer ] )
|
|
143
|
+
# content = renderer.result_with_hash( params )
|
|
144
|
+
|
|
145
|
+
return content
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
end
|