tzispa_helpers 0.2.2 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b8d9b4d815e666c509beeb5c3c5b5446302c3a5f
4
- data.tar.gz: ffd7c7ef51dcdbd5ab14078381ac1c93a5e3f23b
3
+ metadata.gz: 3e89639a5292d45bd73bb24c089a7d2e12a5af5d
4
+ data.tar.gz: a913cbe727b39b40d9e0fdf9cf893c820a42baaf
5
5
  SHA512:
6
- metadata.gz: b1702fe53fe07d1b9d5bff987f38ce1946e0a351e1d2e234441ff01462fc3dd8d9281b0eda134ab569d4950ed619dbb0ab0fa0010aa42c8df3e1bb9f18e53289
7
- data.tar.gz: fde228365de640a6f7ea82fb86b2e133872f51e4242525668f0b15a30ea4279d23b6e3578fd93056c643d585b68282707bd9b228800bcdefdab2d30a04d8ce57
6
+ metadata.gz: 45d66dc9fec88bdb30d7257a82bceb59bc3fb4746b22788e009d0d9f965a26ca041141465f82ffba50b67e0f921ac8b8d9061c9a499a06567d8f45bd5e9617b7
7
+ data.tar.gz: b0c6b9d2f8054c820ea478c3f870811c26b6719ba87b14160bb7be4a902be31a20506bfdfc3e3a2dd48c3c1bbd3472e1ca5403f69f1b7ea8477b0b75569f85cd
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  Tzispa Helpers
2
2
 
3
+ ## v0.3.0
4
+ - bug fixes
5
+ - code refactoring
6
+
3
7
  ## v0.2.2
4
8
  - unscape html request form values
5
9
  - added not_authorized alias method
@@ -1,19 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Tzispa
2
4
  module Helpers
3
5
 
4
- require 'tzispa/helpers/version'
5
- require 'tzispa/helpers/crawler'
6
+ require 'tzispa/helpers/date_time'
7
+ require 'tzispa/helpers/error_view'
6
8
  require 'tzispa/helpers/html'
7
- require 'tzispa/helpers/mail'
8
- require 'tzispa/helpers/mime'
9
9
  require 'tzispa/helpers/pattern'
10
+ require 'tzispa/helpers/provider'
10
11
  require 'tzispa/helpers/request'
12
+ require 'tzispa/helpers/requirer'
11
13
  require 'tzispa/helpers/response'
12
14
  require 'tzispa/helpers/security'
15
+ require 'tzispa/helpers/sign_requirer'
13
16
  require 'tzispa/helpers/text'
14
- require 'tzispa/helpers/provider'
15
- require 'tzispa/helpers/error_view'
16
- require 'tzispa/helpers/recaptcha'
17
+ require 'tzispa/helpers/version'
17
18
 
18
19
  end
19
20
  end
@@ -1,9 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Tzispa
2
4
  module Helpers
3
5
  module DateTime
4
6
 
5
7
  def date_months_diff(date1, date2)
6
- (date2.year - date1.year) * 12 + date2.month - date1.month - (date2.day >= date1.day ? 0 : 1)
8
+ (date2.year - date1.year) * 12 +
9
+ date2.month - date1.month - (date2.day >= date1.day ? 0 : 1)
7
10
  end
8
11
 
9
12
  def date_days_diff(date1, date2)
@@ -1,49 +1,64 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'tzispa/rig/template'
2
4
  require 'tzispa/version'
5
+ require 'tzispa/helpers/services/error_view'
3
6
 
4
7
  module Tzispa
5
8
  module Helpers
6
9
  module ErrorView
7
10
 
8
- def debug_info(exception=nil, status: 500)
9
- String.new.tap { |text|
10
- text << '<!DOCTYPE html>'
11
- text << '<html lang="es"><head>'
12
- text << '<meta charset="utf-8" />'
13
- text << '<style> html {background:#cccccc; font-family:Arial; font-size:15px; color:#555;} body {width:75%; max-width:1200px; margin:18px auto; background:#fff; border-radius:6px; padding:32px 24px;} ul{list-style:none; margin:0; padding:0;} li{font-style:italic; color:#666;} h1 {color:#2ECC71;} </style>'
14
- text << '</head><body>'
15
- text << "<h5>#{Tzispa::FRAMEWORK_NAME} #{Tzispa::VERSION}</h5>\n"
16
- if exception
17
- text << "<h1>#{exception.class.name}</h1><h3>#{exception.message}</h1>\n"
18
- text << '<ol>' + exception.backtrace.map { |trace| "<li>#{trace}</li>\n" }.join + '</ol>' if exception.respond_to?(:backtrace) && exception.backtrace
19
- else
20
- text << "<h1>Error #{status}</h1>\n"
21
- text << "Se ha producido un error inesperado al tramitar la petición"
22
- end
11
+ ERROR_HEADER = <<-ERRORHEADER
12
+ <head>
13
+ <meta charset="utf-8" />
14
+ <style> html {background:#cccccc; font-family:Arial; font-size:15px; color:#555;} body {width:75%; max-width:1200px; margin:18px auto; background:#fff; border-radius:6px; padding:32px 24px;} #main {margin:auto; } ul{list-style:none; margin:0; padding:0;} li{font-style:italic; color:#666;} h1 {color:#2ECC71;} </style>
15
+ </head>
16
+ ERRORHEADER
17
+
18
+ ERROR_PLATFORM_VERSIONS = <<-ERRORPVERSION
19
+ <h6>#{Tzispa::FRAMEWORK_NAME} #{Tzispa::VERSION}</h6>
20
+ ERRORPVERSION
21
+
22
+ def debug_info(ex = nil, status: 500)
23
+ String.new.tap do |text|
24
+ text << '<!DOCTYPE html><html lang="es">'
25
+ text << ERROR_HEADER << '<body>'
26
+ text << ERROR_PLATFORM_VERSIONS
27
+ text << if ex
28
+ srx = Tzispa::Helpers::Services::ErrorView.new ex
29
+ "<h1>#{srx.error_header}\n #{srx.error_backtrace_list}"
30
+ else
31
+ "<h1>Error #{status}</h1>\nSe ha producido un error indeterminado"
32
+ end
23
33
  text << '</body></html>'
24
- }
34
+ end
25
35
  end
26
36
 
27
37
  def error_page(domain, status: 500)
28
- begin
29
- error_file = "#{domain.path}/error/#{status}.htm"
30
- Tzispa::Rig::File.new(error_file).load!.content
31
- rescue
32
- String.new.tap { |text|
33
- text << '<!DOCTYPE html>'
34
- text << '<html lang="es"><head>'
35
- text << '<meta charset="utf-8" />'
36
- text << '<style> html {background:#cccccc; font-family:Arial; font-size:15px; color:#555;} body {width:75%; max-width:1200px; margin:18px auto; background:#fff; border-radius:6px; padding:32px 24px;} #main {margin:auto; } h1 {color:#2ECC71; font-size:4em; text-align:center;} </style>'
37
- text << '</head><body>'
38
- text << '<div id="main">'
39
- text << "<h5>#{Tzispa::FRAMEWORK_NAME} #{Tzispa::VERSION}</h5>\n"
40
- text << "<h1>Error #{status}</h1>\n"
41
- text << '</div>'
42
- text << '</body></html>'
43
- }
38
+ error_file = "#{domain.path}/error/#{status}.htm"
39
+ if (ef = Tzispa::Rig::File.new(error_file)) && ef.exist?
40
+ ef.load!.content
41
+ else
42
+ error_default
44
43
  end
45
44
  end
46
45
 
46
+ def error_log(ex)
47
+ Tzispa::Helpers::Services::ErrorView.new(ex).error_backtrace_log
48
+ end
49
+
50
+ def error_default
51
+ String.new.tap do |text|
52
+ text << '<!DOCTYPE html><html lang="es">'
53
+ text << ERROR_HEADER << '<body>'
54
+ text << '</head><body>'
55
+ text << '<div id="main">'
56
+ text << ERROR_PLATFORM_VERSIONS
57
+ text << "<h1>Error #{status}</h1>\n"
58
+ text << '</div>'
59
+ text << '</body></html>'
60
+ end
61
+ end
47
62
 
48
63
  end
49
64
  end
@@ -20,11 +20,11 @@ module Tzispa
20
20
  end
21
21
 
22
22
  def html_escape(str)
23
- CGI::escapeHTML str
23
+ CGI.escapeHTML str
24
24
  end
25
25
 
26
26
  def html_unescape(str)
27
- CGI::unescapeHTML str
27
+ CGI.unescapeHTML str
28
28
  end
29
29
 
30
30
  def html_urlencode(str)
@@ -36,10 +36,9 @@ module Tzispa
36
36
  end
37
37
 
38
38
  def html_strip(source)
39
- source.gsub(/<\/?[^>]*>/, '')
39
+ source.gsub(%r{/<\/?[^>]*>/}, '')
40
40
  end
41
41
 
42
-
43
42
  #
44
43
  # $Id: sanitize.rb 3 2005-04-05 12:51:14Z dwight $
45
44
  #
@@ -147,7 +146,6 @@ module Tzispa
147
146
  result
148
147
  end
149
148
 
150
-
151
149
  end
152
150
  end
153
151
  end
@@ -9,7 +9,7 @@ module Tzispa
9
9
  def mime_type(type, value = nil)
10
10
  return type if type.nil?
11
11
  return type.to_s if type.to_s.include?('/')
12
- type = ".#{type}" unless type.to_s[0] == ?.
12
+ type = ".#{type}" unless type.to_s[0] == '.'
13
13
  return Rack::Mime.mime_type(type, nil) unless value
14
14
  Rack::Mime::MIME_TYPES[type] = value
15
15
  end
@@ -8,49 +8,47 @@ module Tzispa
8
8
 
9
9
  include Tzispa::Helpers::Html
10
10
 
11
- def pattern_select_hours(selected=nil)
11
+ def pattern_select_hours(selected = nil)
12
12
  selected &&= selected.to_i
13
- Proc.new {
14
- (0..23).map { |hour|
13
+ proc do
14
+ (0..23).map do |hour|
15
15
  loop_item(
16
16
  value: hour,
17
17
  text: hour.to_s.rjust(2, '0'),
18
- selected: html_selected( selected == hour )
18
+ selected: html_selected(selected == hour)
19
19
  )
20
- }
21
- }
20
+ end
21
+ end
22
22
  end
23
23
 
24
- def pattern_select_minutes(selected=nil)
24
+ def pattern_select_minutes(selected = nil)
25
25
  selected &&= selected.to_i
26
- Proc.new {
27
- (0..59).map { |minute|
26
+ proc do
27
+ (0..59).map do |minute|
28
28
  loop_item(
29
29
  value: minute,
30
30
  text: minute.to_s.rjust(2, '0'),
31
- selected: html_selected( selected == minute )
31
+ selected: html_selected(selected == minute)
32
32
  )
33
- }
34
- }
33
+ end
34
+ end
35
35
  end
36
36
 
37
- def pattern_select_year(first, last, selected=nil, reverse=true)
37
+ def pattern_select_year(first, last, selected = nil)
38
38
  selected &&= selected.to_i
39
- Proc.new {
39
+ proc do
40
40
  ryear = (first..last)
41
- enum_year = first > last ? (ryear.first).downto(ryear.last) : (ryear.first).to(ryear.last)
42
- enum_year.map { |year|
41
+ enum_year = first > last ? ryear.first.downto(ryear.last) : ryear.first.to(ryear.last)
42
+ enum_year.map do |year|
43
43
  loop_item(
44
44
  value: year,
45
45
  text: year,
46
- selected: html_selected( selected == year )
46
+ selected: html_selected(selected == year)
47
47
  )
48
- }
49
- }
48
+ end
49
+ end
50
50
  end
51
51
 
52
-
53
-
54
52
  end
55
53
  end
56
54
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Tzispa
2
4
  module Helpers
3
5
  module Provider
@@ -11,13 +13,10 @@ module Tzispa
11
13
  end
12
14
 
13
15
  module ClassMethods
14
-
15
16
  def provides(*args)
16
- (@provides ||= Hash.new).tap { |prv|
17
- args&.each { |s|
18
- prv[s.to_sym] = s
19
- }
20
- }
17
+ (@provides ||= {}).tap do |prv|
18
+ args&.each { |s| prv[s.to_sym] = s }
19
+ end
21
20
  end
22
21
 
23
22
  def provides?(verb)
@@ -28,10 +27,8 @@ module Tzispa
28
27
  def provides_map(source, dest)
29
28
  provides[source] = dest
30
29
  end
31
-
32
30
  end
33
31
 
34
-
35
32
  end
36
33
  end
37
34
  end
@@ -6,59 +6,65 @@ module Tzispa
6
6
  module Helpers
7
7
  module Request
8
8
 
9
- using Tzispa::Utils
9
+ using Tzispa::Utils::TzString
10
10
 
11
11
  def request_data(fields)
12
- Hash.new.tap { |data|
13
- fields.each { |name|
12
+ {}.tap do |data|
13
+ fields.each do |name|
14
14
  macro_field = name.split('@:')
15
15
  macro = macro_field.first.to_sym if macro_field.length == 2
16
16
  field = macro_field.length == 2 ? macro_field.last : macro_field.first
17
- field.split(':').tap { |fld|
18
- src = fld.first
19
- dest = fld.last
20
- value = String == context.request[src] ? String.unescape_html(context.request[src]) : context.request[src]
21
- data[dest.to_sym] = macro ? send(macro, value) : value
22
- }
23
- }
24
- }
17
+ build_field field, macro, data
18
+ end
19
+ end
25
20
  end
26
21
 
27
22
  def request_data_object(data_object:, fields:)
28
- data_object.tap { |data|
29
- fields.each { |name|
23
+ data_object.tap do |data|
24
+ fields.each do |name|
30
25
  macro_field = name.split('@:')
31
26
  macro = macro_field.first.to_sym if macro_field.length == 2
32
27
  field = macro_field.length == 2 ? macro_field.last : macro_field.first
33
- field.split(':').tap { |fld|
34
- src = fld.first
35
- dest = fld.last
36
- value = String == context.request[src] ? String.unescape_html(context.request[src]) : context.request[src]
37
- data.send "#{dest}=".to_sym, macro ? send(macro, value) : value
38
- }
39
- }
40
- }
28
+ build_field field, macro, data
29
+ end
30
+ end
41
31
  end
42
32
 
43
33
  def request_file_upload(request_file:, destination_path:, save_as: nil, keep_ext: true)
44
- if request_file
45
- fileext = File.extname(request_file[:filename]).downcase
46
- filetype = request_file[:type]
47
- save_ext = fileext if keep_ext
48
- filename = (save_as ? "#{save_as}#{save_ext}" : request_file[:filename])
49
- tempfile = request_file[:tempfile]
50
- dest_file = "#{destination_path}/#{filename}"
51
- begin
52
- FileUtils.mkdir_p(destination_path) unless File.exists?(destination_path)
53
- FileUtils.cp tempfile.path, dest_file
54
- ensure
55
- tempfile.close
56
- tempfile.unlink
57
- end
58
- { name: filename, ext: fileext, path: dest_file, size: ::File.size(dest_file), type: filetype }
34
+ return unless request_file
35
+ fileext = File.extname(request_file[:filename]).downcase
36
+ filetype = request_file[:type]
37
+ save_ext = fileext if keep_ext
38
+ filename = (save_as ? "#{save_as}#{save_ext}" : request_file[:filename])
39
+ tempfile = request_file[:tempfile]
40
+ dest_file = "#{destination_path}/#{filename}"
41
+ begin
42
+ FileUtils.mkdir_p(destination_path) unless File.exist?(destination_path)
43
+ FileUtils.cp tempfile.path, dest_file
44
+ ensure
45
+ tempfile.close
46
+ tempfile.unlink
59
47
  end
48
+ { name: filename, ext: fileext, path: dest_file,
49
+ size: ::File.size(dest_file), type: filetype }
60
50
  end
61
51
 
52
+ def build_field(field, macro, data)
53
+ field.split(':').tap do |src, dest|
54
+ dest ||= src
55
+ value = if String == request[src]
56
+ String.unescape_html(request[src])
57
+ else
58
+ request[src]
59
+ end
60
+ value = macro ? send(macro, value) : value
61
+ if data.is_a? ::Hash
62
+ data[dest.to_sym] = value
63
+ else
64
+ data.send "#{dest}=".to_sym, value
65
+ end
66
+ end
67
+ end
62
68
 
63
69
  end
64
70
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Tzispa
2
4
  module Helpers
3
5
  module Requirer
@@ -7,7 +9,7 @@ module Tzispa
7
9
  end
8
10
 
9
11
  def required?(target, value)
10
- self.class.required? target. value
12
+ self.class.required? target, value
11
13
  end
12
14
 
13
15
  def required_valid?(target, value)
@@ -17,10 +19,10 @@ module Tzispa
17
19
  module ClassMethods
18
20
 
19
21
  def required(target, value, &block)
20
- @required ||= Hash.new
21
- (@required[target] ||= Hash.new).tap { |reqt|
22
+ @required ||= {}
23
+ (@required[target] ||= {}).tap do |reqt|
22
24
  reqt[value] = block || true
23
- }
25
+ end
24
26
  end
25
27
 
26
28
  def required?(target, value)
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'uri'
4
4
  require_relative 'mime'
5
+ require_relative 'services/send_file'
6
+ require_relative 'services/content_type'
5
7
 
6
8
  module Tzispa
7
9
  module Helpers
@@ -23,10 +25,14 @@ module Tzispa
23
25
  # evaluation is deferred until the body is read with #each.
24
26
  def body(value = nil, &block)
25
27
  if block_given?
26
- def block.each; yield(call) end
28
+ def block.each
29
+ yield(call)
30
+ end
27
31
  response.body = block
28
32
  elsif value
29
- headers.delete 'Content-Length' unless request.head? || value.is_a?(Rack::File) || value.is_a?(Stream)
33
+ headers.delete 'Content-Length' unless request.head? ||
34
+ value.is_a?(Rack::File) ||
35
+ value.is_a?(Stream)
30
36
  response.body = value
31
37
  else
32
38
  response.body
@@ -42,14 +48,7 @@ module Tzispa
42
48
 
43
49
  # Halt processing and redirect to the URI provided.
44
50
  def redirect(uri, absolute, *args)
45
- if (env['HTTP_VERSION'] == 'HTTP/1.1' || env['HTTP_VERSION'] == 'HTTP/2.0') && env["REQUEST_METHOD"] != 'GET'
46
- status 303
47
- else
48
- status 302
49
- end
50
-
51
- # According to RFC 2616 section 14.30, "the field value consists of a
52
- # single absolute URI"
51
+ status(request.allowed_http_version? && request.get? ? 303 : 302)
53
52
  response['Location'] = uri(uri.to_s, absolute)
54
53
  halt(*args)
55
54
  end
@@ -61,27 +60,30 @@ module Tzispa
61
60
  halt(*args)
62
61
  end
63
62
 
64
-
65
63
  # Generates the absolute URI for a given path in the app.
66
64
  # Takes Rack routers and reverse proxies into account.
67
65
  def uri(addr = nil, absolute = true)
68
- return addr if addr =~ /\A[A-z][A-z0-9\+\.\-]*:/
66
+ return addr if addr.match?(/\A[A-z][A-z0-9\+\.\-]*:/)
69
67
  uri = [host = String.new]
70
- if absolute
71
- host << "http#{'s' if request.secure?}://"
72
- if request.forwarded? or request.port != (request.secure? ? 443 : 80)
73
- host << request.host_with_port
74
- else
75
- host << request.host
76
- end
77
- end
68
+ host << uri_host if absolute
78
69
  uri << (addr ? addr : request.path_info).to_s
79
70
  File.join uri
80
71
  end
81
72
 
73
+ def uri_host
74
+ String.new.tap do |host|
75
+ host << "http#{'s' if request.secure?}://"
76
+ host << (uri_port? ? request.host_with_port : request.host)
77
+ end
78
+ end
79
+
80
+ def uri_port?
81
+ request.forwarded? || request.port != (request.secure? ? 443 : 80)
82
+ end
83
+
82
84
  # Halt processing and return the error status provided.
83
- def error(code, body = nil)
84
- code, body = 500, code.to_str if code.respond_to? :to_str
85
+ def error(code = 500, body = nil)
86
+ body = code.to_str if code.respond_to? :to_str
85
87
  response.body = body unless body.nil?
86
88
  halt code
87
89
  end
@@ -95,7 +97,7 @@ module Tzispa
95
97
  def unauthorized(body = nil)
96
98
  error 401, body
97
99
  end
98
- alias_method :not_authorized, :unauthorized
100
+ alias not_authorized unauthorized
99
101
 
100
102
  # Set multiple response headers with Hash.
101
103
  def headers(hash = nil)
@@ -106,55 +108,17 @@ module Tzispa
106
108
  # Set the Content-Type of the response body given a media type or file
107
109
  # extension.
108
110
  def content_type(type = nil, params = {})
109
- return response['Content-Type'] unless type
110
- default = params.delete :default
111
- mime_type = mime_type(type) || default
112
- fail "Unknown media type: %p" % type if mime_type.nil?
113
- mime_type = mime_type.dup
114
- unless params.include? :charset
115
- params[:charset] = params.delete('charset') || config.default_encoding
116
- end
117
- params.delete :charset if mime_type.include? 'charset'
118
- unless params.empty?
119
- mime_type << (mime_type.include?(';') ? ', ' : ';')
120
- mime_type << params.map do |key, val|
121
- val = val.inspect if val =~ /[";,]/
122
- "#{key}=#{val}"
123
- end.join(', ')
124
- end
125
- response['Content-Type'] = mime_type
126
- end
127
-
128
- def attachment!(filename = nil, disposition = 'attachment')
129
- content_disposition = disposition.to_s
130
- content_disposition += "; filename=\"#{filename}\"; filename*=UTF-8''#{URI.escape(filename)}" if !filename.nil?
131
- response['Content-Disposition'] = content_disposition
111
+ return if response.drop_content_info?
112
+ ct = Tzispa::Helpers::Services::ContentType.new(response,
113
+ config.default_encoding)
114
+ ct.header(type, params)
132
115
  end
133
116
 
134
117
  def send_file(path, opts = {})
135
- begin
136
- if opts[:type] or not response['Content-Type']
137
- content_type opts[:type] || opts[:extension], :default => 'application/octet-stream'
138
- end
139
-
140
- disposition = opts[:disposition]
141
- filename = opts[:filename]
142
- disposition = 'attachment' if disposition.nil? and filename
143
- filename = path if filename.nil?
144
-
145
- attachment! filename, disposition
146
- last_modified opts[:last_modified] if opts[:last_modified]
147
-
148
- file = Rack::File.new(Dir.pwd)
149
- result = file.serving(request, path)
150
-
151
- result[1].each { |k,v| response.headers[k] ||= v }
152
- response.headers['Content-Length'] = result[1]['Content-Length']
153
- response.status = result[0]
154
- response.body = result[2]
155
- rescue
156
- not_found 'Fichero no encontrado'
157
- end
118
+ not_found unless ::File.exist? path
119
+ file = Rack::File.new(Dir.pwd)
120
+ fss = Tzispa::Helpers::Services::SendFile.new response, path, opts
121
+ fss.send file.serving(request, path)
158
122
  end
159
123
 
160
124
  # Sugar for redirect (example: redirect back)
@@ -192,12 +156,16 @@ module Tzispa
192
156
  response.status == 404
193
157
  end
194
158
 
159
+ def error_500(str)
160
+ 500.tap { |_code| response.body = str if str }
161
+ end
195
162
 
196
163
  class NotFound < NameError #:nodoc:
197
- def http_status; 404 end
164
+ def http_status
165
+ 404
166
+ end
198
167
  end
199
168
 
200
-
201
169
  end
202
170
  end
203
171
  end
@@ -6,57 +6,46 @@ module Tzispa
6
6
  module Helpers
7
7
  module Security
8
8
 
9
-
10
9
  def secret(length)
11
- alfanb = (['!', '"', '·', '$', '%', '&', '/', '(', ')', '=', '?', '+',
12
- '@', '#', ',', '.', '-', ';', ':', '_', '[', ']', '>', '<', '*'] <<
13
- [('a'..'z'), ('0'..'9'), ('A'..'Z')].map { |i| i.to_a }).flatten
10
+ alfanb = (['!', '"', '·', '$', '%', '&', '/', '(', ')', '=',
11
+ '?', '+', '@', '#', ',', '.', '-', ';', ':', '_',
12
+ '[', ']', '>', '<', '*'] <<
13
+ [('a'..'z'), ('0'..'9'), ('A'..'Z')].map(&:to_a)).flatten
14
14
  (0...length).map { alfanb[rand(alfanb.length)] }.join
15
15
  end
16
16
 
17
17
  def uuid
18
- sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
19
- # 32 bits for "time_low"
20
- rand(0..0xffff), rand(0..0xffff),
21
-
22
- # 16 bits for "time_mid"
23
- rand(0..0xffff),
24
-
25
- # 16 bits for "time_hi_and_version",
26
- #3 four most significant bits holds version number 4
27
- rand(0..0x0fff) | 0x4000,
28
-
29
- # 16 bits, 8 bits for "clk_seq_hi_res",
30
- # 8 bits for "clk_seq_low",
31
- # two most significant bits holds zero and one for variant DCE1.1
32
- rand(0..0x3fff) | 0x8000,
33
-
34
- # 48 bits for "node"
35
- rand(0..0xffff), rand(0..0xffff), rand(0..0xffff)
36
- )
18
+ format('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
19
+ rand(0..0xffff),
20
+ rand(0..0xffff),
21
+ rand(0..0xffff),
22
+ rand(0..0x0fff) | 0x4000,
23
+ rand(0..0x3fff) | 0x8000,
24
+ rand(0..0xffff),
25
+ rand(0..0xffff),
26
+ rand(0..0xffff))
37
27
  end
38
28
 
39
- def sign_array(astr, salt=nil)
40
- sign, i = String.new, 0
41
- astr.each { |s|
42
- i = i + 1
43
- sign << "#{"_"*i}#{s}"
44
- }
29
+ def sign_array(astr, salt = nil)
30
+ sign = String.new
31
+ i = 0
32
+ astr.each do |s|
33
+ i += 1
34
+ sign << "#{'_' * i}#{s}"
35
+ end
45
36
  sign << "**#{salt}"
46
37
  Digest::SHA1.hexdigest sign
47
38
  end
48
39
 
49
40
  def hash_password(password, salt)
50
- Digest::MD5::hexdigest "#{password}::#{salt}"
41
+ Digest::MD5.hexdigest "#{password}::#{salt}"
51
42
  end
52
43
 
53
44
  def hash_password?(hashed, pwd, salt)
54
45
  hashed == hash_password(pwd, salt)
55
46
  end
56
47
 
57
-
58
48
  class Identity
59
-
60
49
  attr_reader :id, :token
61
50
 
62
51
  def initialize(id, secret)
@@ -68,15 +57,11 @@ module Tzispa
68
57
  @token == Identity.generate_token(@id, secret)
69
58
  end
70
59
 
71
- private
72
-
73
60
  def self.generate_token(value, salt)
74
61
  Digest::SHA1.hexdigest "___#{value}_#{salt}__token__"
75
62
  end
76
-
77
63
  end
78
64
 
79
-
80
65
  end
81
66
  end
82
67
  end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+ require 'tzispa/helpers/mime'
5
+
6
+ module Tzispa
7
+ module Helpers
8
+ module Services
9
+
10
+ class ContentType
11
+ include Tzispa::Helpers::Mime
12
+
13
+ attr_reader :response, :default_encoding
14
+
15
+ def initialize(response, default_encoding = nil)
16
+ @response = response
17
+ @default_encoding = default_encoding
18
+ end
19
+
20
+ # Set the Content-Type of the response body given a media type or file
21
+ # extension.
22
+ def header(type = nil, params = {})
23
+ return response['Content-Type'] unless type || params[:default]
24
+ default = params.delete :default
25
+ mime = mime_type(type) || default
26
+ raise "Unknown media type: #{type}" unless mime
27
+ params = charset mime, params
28
+ build mime.dup, params
29
+ end
30
+
31
+ def charset(mime, params)
32
+ unless params.include?(:charset) || mime.include?('charset')
33
+ params[:charset] = params.delete('charset') || default_encoding
34
+ end
35
+ params.delete :charset if mime.include? 'charset'
36
+ params
37
+ end
38
+
39
+ def file(type, extension = nil)
40
+ return unless response['Content-Type']
41
+ header type || extension,
42
+ default: 'application/octet-stream'
43
+ end
44
+
45
+ private
46
+
47
+ def build(mime, params)
48
+ mime if params.empty?
49
+ mime << (mime.include?(';') ? ', ' : ';')
50
+ mime << params.select { |_, val| val&.match?(/[";,]/) }
51
+ .map do |key, val|
52
+ "#{key}=#{val.inspect}"
53
+ end.join(', ')
54
+ response['Content-Type'] = mime
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tzispa
4
+ module Helpers
5
+ module Services
6
+
7
+ class ErrorView
8
+ attr_reader :exception
9
+
10
+ def initialize(exception)
11
+ @exception = exception
12
+ end
13
+
14
+ def error_header
15
+ "<h1>#{exception.class.name}</h1><h3>#{exception.message}</h3>"
16
+ end
17
+
18
+ def error_backtrace_list
19
+ return unless exception.respond_to?(:backtrace) && exception.backtrace
20
+ String.new.tap do |str|
21
+ str << '<ol>'
22
+ str << exception.backtrace.map { |trace| "<li>#{trace}</li>\n" }.join
23
+ str << '</ol>'
24
+ end
25
+ end
26
+
27
+ def error_backtrace_log
28
+ return unless exception.respond_to?(:backtrace) && exception.backtrace
29
+ String.new.tap do |str|
30
+ str << "#{exception.class.name}: #{exception}:\n"
31
+ str << exception.backtrace.join("\n")
32
+ end
33
+ end
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+
5
+ module Tzispa
6
+ module Helpers
7
+ module Services
8
+
9
+ class SendFile
10
+ attr_reader :response, :opts, :path
11
+
12
+ def initialize(response, path, opts)
13
+ @response = response
14
+ @opts = opts
15
+ @path = path
16
+ end
17
+
18
+ def content_disposition(filename = nil, disposition = 'attachment')
19
+ disposition = String.new << disposition.to_s
20
+ if filename
21
+ escaped = URI.escape(filename)
22
+ disposition << "; filename=\"#{escaped}\""
23
+ disposition << "; filename*=UTF-8''#{escaped}"
24
+ end
25
+ response['Content-Disposition'] = disposition
26
+ end
27
+
28
+ def send(result)
29
+ prepare
30
+ response.status = result[0]
31
+ if response.status.between? 200, 299
32
+ headers_set result[1]
33
+ response.body = result[2]
34
+ end
35
+ response
36
+ end
37
+
38
+ private
39
+
40
+ def prepare
41
+ content_headers
42
+ disposition = opts[:disposition]
43
+ filename = opts[:filename]
44
+ disposition = 'attachment' if disposition.nil? && filename
45
+ filename = path if filename.nil?
46
+ content_disposition filename, disposition
47
+ end
48
+
49
+ def headers_set(headers)
50
+ headers.each { |k, v| response.headers[k] ||= v }
51
+ response.headers['Content-Length'] = headers['Content-Length']
52
+ response.no_cache.cache_private if opts[:no_cache]
53
+ end
54
+
55
+ def content_headers
56
+ ct = Tzispa::Helpers::Services::ContentType.new response
57
+ ct.file opts[:type], opts[:extension]
58
+ last_modified opts[:last_modified] if opts[:last_modified]
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+ require 'tzispa/helpers/session_flash_bag'
5
+
6
+ module Tzispa
7
+ module Helpers
8
+ module Session
9
+
10
+ SESSION_LAST_ACCESS = :__last_access
11
+ SESSION_ID = :__session_id
12
+ SESSION_AUTH_USER = :__auth__user
13
+ GLOBAL_MESSAGE_FLASH = :__global_message_flash
14
+
15
+ def init_session
16
+ generate_session_id if config&.sessions&.enabled && !session?
17
+ end
18
+
19
+ def set_last_access
20
+ session[SESSION_LAST_ACCESS] = Time.now.utc.iso8601
21
+ end
22
+
23
+ def last_access
24
+ session[SESSION_LAST_ACCESS]
25
+ end
26
+
27
+ def flash
28
+ @flash ||= SessionFlashBag.new(session, GLOBAL_MESSAGE_FLASH)
29
+ end
30
+
31
+ def session?
32
+ !session[SESSION_ID].nil? && (session[SESSION_ID] == session.id)
33
+ end
34
+
35
+ def logged?
36
+ session? && login
37
+ end
38
+
39
+ def login=(user)
40
+ session[SESSION_AUTH_USER] = user unless user.nil?
41
+ end
42
+
43
+ def login
44
+ session[SESSION_AUTH_USER]
45
+ end
46
+
47
+ def logout
48
+ session.delete(SESSION_AUTH_USER)
49
+ end
50
+
51
+ def generate_session_id
52
+ SecureRandom.uuid.tap do |uuid|
53
+ session.id = uuid
54
+ session[SESSION_ID] = uuid
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'json'
5
+
6
+ module Tzispa
7
+ module Helpers
8
+ module Session
9
+
10
+ class SessionFlashBag
11
+ extend Forwardable
12
+
13
+ def_delegators :@bag, :count, :length, :size, :each
14
+
15
+ SESSION_FLASH_BAG = :__flash_bag
16
+
17
+ def initialize(session, key)
18
+ @session = session
19
+ @session_key = "#{SESSION_FLASH_BAG}_#{key}".to_sym
20
+ load!
21
+ end
22
+
23
+ def <<(value)
24
+ return unless value
25
+ bag << value
26
+ store
27
+ end
28
+
29
+ def pop
30
+ value = bag.pop
31
+ store
32
+ value
33
+ end
34
+
35
+ def pop_all
36
+ empty!
37
+ bag
38
+ end
39
+
40
+ def push(value)
41
+ bag.push value
42
+ store
43
+ end
44
+
45
+ private
46
+
47
+ attr_reader :bag, :session, :session_key
48
+
49
+ def load!
50
+ @bag = session[session_key] ? JSON.parse(session[session_key]) : []
51
+ end
52
+
53
+ def store
54
+ session[session_key] = bag.to_json
55
+ end
56
+
57
+ def empty!
58
+ session[session_key] = []
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'requirer'
2
4
 
3
5
  module Tzispa
@@ -17,9 +19,7 @@ module Tzispa
17
19
  self.class.sign_valid? self
18
20
  end
19
21
 
20
-
21
22
  module ClassMethods
22
-
23
23
  def sign_required!(&block)
24
24
  required(:router_params, :sign, &block)
25
25
  end
@@ -31,7 +31,6 @@ module Tzispa
31
31
  def sign_valid?(obj)
32
32
  required_valid? :router_params, :sign, obj
33
33
  end
34
-
35
34
  end
36
35
 
37
36
  end
@@ -3,7 +3,7 @@
3
3
  require 'date'
4
4
  require 'bigdecimal'
5
5
  require 'i18n'
6
- require "unicode_utils"
6
+ require 'unicode_utils'
7
7
  require 'cgi/util'
8
8
 
9
9
  module Tzispa
@@ -11,13 +11,11 @@ module Tzispa
11
11
  module Text
12
12
 
13
13
  def remove_words(sentence, removable)
14
- sentence.split.delete_if{|x| removable.include?(UnicodeUtils.downcase x)}.join(' ')
14
+ sentence.split.delete_if { |x| removable.include? UnicodeUtils.downcase(x) }.join(' ')
15
15
  end
16
16
 
17
17
  def remove_phrases(text, removable)
18
- removable.each { |phrase|
19
- text.slice! phrase
20
- }
18
+ removable.each { |phrase| text.slice! phrase }
21
19
  text
22
20
  end
23
21
 
@@ -26,68 +24,67 @@ module Tzispa
26
24
  end
27
25
 
28
26
  def synonymize(sentence, synonyms)
29
- sentence.gsub(/[[:alnum:]]+/) {|word|
27
+ sentence.gsub(/[[:alnum:]]+/) do |word|
30
28
  dwword = UnicodeUtils.downcase word
31
- synonyms.has_key?(dwword) ? synonyms[dwword] : word
32
- }
29
+ synonyms.key?(dwword) ? synonyms[dwword] : word
30
+ end
33
31
  end
34
32
 
35
33
  def strip_to_nil(str, transform = nil)
36
- sstr = str.strip if str and not str.strip.empty?
34
+ sstr = str.strip if str && !str.strip.empty?
37
35
  case transform
38
- when :upcase then
39
- UnicodeUtils.upcase(sstr)
40
- when :downcase then
41
- UnicodeUtils.downcase(sstr)
42
- when :titlecase then
43
- UnicodeUtils.titlecase(sstr)
44
- else sstr
36
+ when :upcase then
37
+ UnicodeUtils.upcase(sstr)
38
+ when :downcase then
39
+ UnicodeUtils.downcase(sstr)
40
+ when :titlecase then
41
+ UnicodeUtils.titlecase(sstr)
42
+ else
43
+ sstr
45
44
  end
46
45
  end
47
46
 
48
47
  def html_unscape(str)
49
- CGI::unescapeHTML(str.strip) if str && !str.strip.empty?
48
+ CGI.unescapeHTML(str.strip) if str && !str.strip.empty?
50
49
  end
51
50
 
52
- def split_to_array(str, separator=';')
53
- str.split(separator) if str
51
+ def split_to_array(str, separator = ';')
52
+ str&.split(separator)
54
53
  end
55
54
 
56
55
  def join_to_nil(ary, separator)
57
- ary.join(separator) if ary and not ary.empty?
56
+ ary.join(separator) if ary && !ary.empty?
58
57
  end
59
58
 
60
- def str_to_bool(str, strue=nil)
59
+ def str_to_bool(str, strue = nil)
61
60
  strue ? (strue == str) : (str == 'yes' || str == 'true')
62
61
  end
63
62
 
64
- def str_to_date(str, format=nil)
63
+ def str_to_date(str, format = nil)
65
64
  str = strip_to_nil str
66
65
  Date.strptime(str, format || I18n.t('date.formats.default')) if str
67
66
  end
68
67
 
69
- def str_to_datetime(str, format=nil)
68
+ def str_to_datetime(str, format = nil)
70
69
  str = strip_to_nil str
71
70
  DateTime.strptime(str, format || I18n.t('datetime.formats.default'))
72
71
  end
73
72
 
74
- def str_time_ellapsed(t_start, t_end=nil)
73
+ def str_time_ellapsed(t_start, t_end = nil)
75
74
  elapsed = (t_end || Time.now) - t_start
76
75
  seconds = elapsed % 60
77
76
  minutes = (elapsed / 60) % 60
78
77
  hours = elapsed / (60 * 60)
79
- format("%02d:%02d:%02d", hours, minutes, seconds)
78
+ format('%02d:%02d:%02d', hours, minutes, seconds)
80
79
  end
81
80
 
82
81
  def str_to_amount(str, options = {})
83
- if str && !str.strip.empty?
84
- separator = options.fetch(:separator, I18n.t('number.currency.format.separator'))
85
- precision = options.fetch(:precision, I18n.t('number.currency.format.precision'))
86
- re = Regexp.new "[^\\d\\#{separator}\\-]"
87
- str = str.gsub(re, '')
88
- str = str.gsub(separator, '.') if separator != '.'
89
- BigDecimal.new(str).round(precision).to_s('F')
90
- end
82
+ return unless !str || str.strip.empty?
83
+ separator = options.fetch(:separator, I18n.t('number.currency.format.separator'))
84
+ precision = options.fetch(:precision, I18n.t('number.currency.format.precision'))
85
+ str = str.gsub(Regexp.new("[^\\d\\#{separator}\\-]"), '')
86
+ str = str.gsub(separator, '.') if separator != '.'
87
+ BigDecimal.new(str).round(precision).to_s('F')
91
88
  end
92
89
 
93
90
  def amount(number, options = {})
@@ -106,30 +103,34 @@ module Tzispa
106
103
  separator = options.fetch(:separator, I18n.t('number.currency.format.separator'))
107
104
  delimiter = options.fetch(:delimiter, I18n.t('number.currency.format.delimiter')).to_s
108
105
  minimum_precision = options[:minimum_precision] || 0
109
- str = number.is_a?(BigDecimal) ? number.to_s('F').sub(/\.0+\z/, "") : number.to_s.sub(/\.0+\z/, "")
110
- str =~ /\A(\-?)(\d+)(?:\.(\d+))?\z/ or raise "Could not parse number: #{number}"
111
- sign = $1
112
- integer = $2
113
- fraction = ($3 || '')
106
+ str = if number.is_a?(BigDecimal)
107
+ number.to_s('F').sub(/\.0+\z/, '')
108
+ else
109
+ number.to_s.sub(/\.0+\z/, '')
110
+ end
111
+ smatch = str.match(/\A(\-?)(\d+)(?:\.(\d+))?\z/)
112
+ raise "Could not parse number: #{number}" unless smatch
113
+ sign = smatch[1]
114
+ integer = smatch[2]
115
+ fraction = (smatch[3] || '')
114
116
 
115
117
  if options[:maximum_precision]
116
118
  fraction = fraction[0, options[:maximum_precision]] if options[:maximum_precision]
117
119
  end
118
120
 
119
-
120
- if fraction.length > 0 && minimum_precision > 0
121
+ if fraction.positive? && minimum_precision.positive?
121
122
  fraction = "#{fraction}#{'0' * [0, minimum_precision - fraction.length].max}"
122
- elsif minimum_precision == 0 && fraction.length > 0 && fraction.to_i == 0
123
+ elsif minimum_precision.zero? && !fraction.empty? && fraction.to_i.zero?
123
124
  fraction = ''
124
125
  end
125
126
 
126
- # the following two lines appear to be the most performant way to add a delimiter to every thousands place in the number
127
+ # add a delimiter to every thousands place in the number
127
128
  integer_size = integer.size
128
- (1..((integer_size-1) / 3)).each {|x| integer[integer_size-x*3,0] = delimiter}
129
+ (1..((integer_size - 1) / 3)).each { |x| integer[integer_size - x * 3, 0] = delimiter }
129
130
  str = integer.chomp(delimiter)
130
131
 
131
132
  # add fraction
132
- str << "#{separator}#{fraction}" if fraction.length > 0
133
+ str << "#{separator}#{fraction}" unless fraction.empty?
133
134
 
134
135
  # restore sign
135
136
  str = "#{sign}#{str}"
@@ -145,22 +146,26 @@ module Tzispa
145
146
  end
146
147
 
147
148
  def money_amount(number, options = {})
148
- amount(number, options.merge(:unit => I18n.t('number.currency.format.unit'), :nil_as_dash => false, :precision => I18n.t('number.currency.format.precision'), minimum_precision: 0))
149
+ amount(number, options.merge(unit: I18n.t('number.currency.format.unit'),
150
+ nil_as_dash: false,
151
+ precision: I18n.t('number.currency.format.precision'),
152
+ minimum_precision: 0))
149
153
  end
150
154
 
151
155
  def price_amount(number, options = {})
152
- amount(number, options.merge(:nil_as_dash => false, :precision => I18n.t('number.currency.format.precision'), minimum_precision: 0))
156
+ amount(number, options.merge(nil_as_dash: false,
157
+ precision: I18n.t('number.currency.format.precision'),
158
+ minimum_precision: 0))
153
159
  end
154
160
 
155
161
  def starinizer(rating, star_value, max_stars)
156
- Hash.new.tap { |stars|
162
+ {}.tap do |stars|
157
163
  stars[:full] = rating / star_value
158
164
  stars[:half] = rating % star_value
159
165
  stars[:o] = max_stars - stars[:full] - stars[:half]
160
- }
166
+ end
161
167
  end
162
168
 
163
-
164
169
  end
165
170
  end
166
171
  end
@@ -3,7 +3,7 @@
3
3
  module Tzispa
4
4
  module Helpers
5
5
 
6
- VERSION = '0.2.2'
6
+ VERSION = '0.3.0'
7
7
  NAME = 'Tzispa Helpers'
8
8
  GEM_NAME = 'tzispa_helpers'
9
9
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tzispa_helpers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Antonio Piñero
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-13 00:00:00.000000000 Z
11
+ date: 2017-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -64,7 +64,6 @@ files:
64
64
  - lib/tzispa/helpers.rb
65
65
  - lib/tzispa/helpers/date_time.rb
66
66
  - lib/tzispa/helpers/error_view.rb
67
- - lib/tzispa/helpers/hash_trans.rb
68
67
  - lib/tzispa/helpers/html.rb
69
68
  - lib/tzispa/helpers/mime.rb
70
69
  - lib/tzispa/helpers/pattern.rb
@@ -73,6 +72,11 @@ files:
73
72
  - lib/tzispa/helpers/requirer.rb
74
73
  - lib/tzispa/helpers/response.rb
75
74
  - lib/tzispa/helpers/security.rb
75
+ - lib/tzispa/helpers/services/content_type.rb
76
+ - lib/tzispa/helpers/services/error_view.rb
77
+ - lib/tzispa/helpers/services/send_file.rb
78
+ - lib/tzispa/helpers/session.rb
79
+ - lib/tzispa/helpers/session_flash_bag.rb
76
80
  - lib/tzispa/helpers/sign_requirer.rb
77
81
  - lib/tzispa/helpers/text.rb
78
82
  - lib/tzispa/helpers/version.rb
@@ -1,18 +0,0 @@
1
- module Tzispa
2
- module Helpers
3
- module HashTrans
4
-
5
- def hash_fussion!(hash, fussion_keys={})
6
- hash.keys.each { |key|
7
- if fussion_keys.has_key?(key)
8
- hash[fussion_keys[key]] ?
9
- hash[fussion_keys[key]] += hash[key] :
10
- hash[fussion_keys[key]] = hash[key]
11
- hash.delete(key)
12
- end
13
- } unless fussion_keys.empty?
14
- end
15
-
16
- end
17
- end
18
- end