shaf 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/shaf/extensions.rb +4 -0
- data/lib/shaf/extensions/authorize.rb +1 -1
- data/lib/shaf/extensions/current_user.rb +44 -0
- data/lib/shaf/extensions/resource_uris.rb +47 -13
- data/lib/shaf/extensions/symbolic_routes.rb +27 -0
- data/lib/shaf/formable.rb +19 -3
- data/lib/shaf/generator/policy.rb +1 -0
- data/lib/shaf/generator/templates/api/controller.rb.erb +37 -26
- data/lib/shaf/generator/templates/api/policy.rb.erb +4 -1
- data/lib/shaf/helpers.rb +0 -2
- data/lib/shaf/helpers/payload.rb +7 -3
- data/lib/shaf/spec/http_method_utils.rb +3 -4
- data/lib/shaf/spec/integration_spec.rb +10 -1
- data/lib/shaf/spec/payload_utils.rb +11 -38
- data/lib/shaf/tasks/test.rb +5 -0
- data/lib/shaf/version.rb +1 -1
- data/templates/api/controllers/base_controller.rb +10 -3
- data/templates/api/controllers/docs_controller.rb +4 -3
- data/templates/api/controllers/root_controller.rb +1 -1
- data/templates/api/serializers/form_serializer.rb +6 -2
- data/templates/config/constants.rb +2 -0
- data/templates/config/directories.rb +13 -1
- metadata +4 -3
- metadata.gz.sig +0 -0
- data/lib/shaf/helpers/session.rb +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45e90f32663688a63993bcf1aa79c6c9b8667d11dbfc9a5fdba50141e983ea53
|
4
|
+
data.tar.gz: 919292b331cc09ce95031e4d1e723371114fef9e86b6d97c2e90e816befb0d77
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 788b01fd3f933f9e86ef99c9b51c14768208f73c5dc3cf4fe0a39fcb19078f82eb7eaaa2a1dcfc33d4d1a44980dc66254693a240b2e2b28d4a6e6b0d0383b676
|
7
|
+
data.tar.gz: a07510311e28e5008991d5461f9c2e97485640cd146a8304874bc216888eb722c941c266dc74b59b184ca3ea302b6a508a315421ed040dd64c2d111ea80548c7
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/lib/shaf/extensions.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
require 'shaf/extensions/resource_uris'
|
2
|
+
require 'shaf/extensions/current_user'
|
2
3
|
require 'shaf/extensions/authorize'
|
4
|
+
require 'shaf/extensions/symbolic_routes'
|
3
5
|
|
4
6
|
module Shaf
|
5
7
|
def self.extensions
|
6
8
|
[
|
7
9
|
ResourceUris,
|
10
|
+
CurrentUser,
|
8
11
|
Authorize,
|
12
|
+
SymbolicRoutes
|
9
13
|
]
|
10
14
|
end
|
11
15
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'digest'
|
2
|
+
|
3
|
+
module Shaf
|
4
|
+
module CurrentUser
|
5
|
+
def self.registered(app)
|
6
|
+
return unless app.respond_to?(:current_user) && app.current_user
|
7
|
+
|
8
|
+
app.log.info 'Using Shaf::CurrentUser'
|
9
|
+
app.helpers Helpers
|
10
|
+
end
|
11
|
+
|
12
|
+
def lookup_user_with(&block)
|
13
|
+
unless block_given? && block.respond_to?(:call)
|
14
|
+
raise ArgumentError, '::lookup_user_with requires a block argument'
|
15
|
+
end
|
16
|
+
log.info 'Using custom current_user lookup'
|
17
|
+
Helpers.lookup_proc = block
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Helpers
|
22
|
+
class << self
|
23
|
+
attr_accessor :lookup_proc
|
24
|
+
|
25
|
+
def user_lookup(request, token)
|
26
|
+
return lookup_proc.call(token, request) if lookup_proc
|
27
|
+
return unless token
|
28
|
+
digest = Digest::SHA256.hexdigest(token)
|
29
|
+
User.where(auth_token_digest: digest).first
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def current_user
|
34
|
+
return @current_user if defined?(@current_user)
|
35
|
+
header = settings.auth_token_header
|
36
|
+
token = request.env[header]
|
37
|
+
@current_user = Helpers.user_lookup(request, token)
|
38
|
+
end
|
39
|
+
|
40
|
+
def authenticated?
|
41
|
+
!current_user.nil?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -4,7 +4,8 @@ module Shaf
|
|
4
4
|
module ResourceUris
|
5
5
|
def resource_uris_for(*args)
|
6
6
|
CreateUriMethods.new(*args).call
|
7
|
-
|
7
|
+
|
8
|
+
include UriHelper unless self < UriHelper
|
8
9
|
end
|
9
10
|
|
10
11
|
def register_uri(name, uri)
|
@@ -13,6 +14,9 @@ module Shaf
|
|
13
14
|
end
|
14
15
|
method_string = MethodBuilder.as_string(name, uri)
|
15
16
|
UriHelperMethods.eval_method(method_string)
|
17
|
+
UriHelperMethods.register(MethodBuilder.template_method_name(name)) { uri.dup.freeze }
|
18
|
+
|
19
|
+
include UriHelper unless self < UriHelper
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
@@ -31,6 +35,10 @@ module Shaf
|
|
31
35
|
module UriHelper
|
32
36
|
extend UriHelperMethods
|
33
37
|
include UriHelperMethods
|
38
|
+
|
39
|
+
def self.included(mod)
|
40
|
+
mod.extend self
|
41
|
+
end
|
34
42
|
end
|
35
43
|
|
36
44
|
# This class register uri helper methods like:
|
@@ -39,6 +47,12 @@ module Shaf
|
|
39
47
|
# new_book_uri => /books/form
|
40
48
|
# edit_book_uri(book) => /books/5/edit
|
41
49
|
#
|
50
|
+
# And uri template methods:
|
51
|
+
# books_uri_template => /books
|
52
|
+
# book_uri_template => /books/:id
|
53
|
+
# new_book_uri_template => /books/form
|
54
|
+
# edit_book_uri_template => /books/:id/edit
|
55
|
+
#
|
42
56
|
class CreateUriMethods
|
43
57
|
def initialize(name, base: nil, plural_name: nil)
|
44
58
|
@name = name.to_s
|
@@ -62,17 +76,23 @@ module Shaf
|
|
62
76
|
attr_reader :name, :base, :plural_name
|
63
77
|
|
64
78
|
def register_resources_uri
|
65
|
-
uri = "#{base}/#{plural_name}"
|
66
|
-
|
67
|
-
|
68
|
-
|
79
|
+
uri = "#{base}/#{plural_name}".freeze
|
80
|
+
|
81
|
+
UriHelperMethods.register("#{plural_name}_uri") { uri }
|
82
|
+
UriHelperMethods.register("#{plural_name}_uri_template") { uri }
|
69
83
|
end
|
70
84
|
|
71
85
|
def register_resource_uri
|
72
86
|
uri = "#{base}/#{plural_name}"
|
87
|
+
|
73
88
|
UriHelperMethods.register "#{name}_uri" do |resrc|
|
74
89
|
id = resrc.is_a?(Integer) ? resrc : resrc&.id
|
75
|
-
"#{
|
90
|
+
raise ArgumentError, "id must be an integer! was #{id.class}" unless id.is_a?(Integer)
|
91
|
+
"#{uri}/#{id}".freeze
|
92
|
+
end
|
93
|
+
|
94
|
+
UriHelperMethods.register "#{name}_uri_template" do
|
95
|
+
"#{uri}/:id".freeze
|
76
96
|
end
|
77
97
|
end
|
78
98
|
|
@@ -83,27 +103,37 @@ module Shaf
|
|
83
103
|
uri = "#{base}/#{plural_name}"
|
84
104
|
UriHelperMethods.register "#{plural_name}_uri" do |resrc = nil|
|
85
105
|
if resrc.nil?
|
86
|
-
uri.
|
106
|
+
uri.freeze
|
87
107
|
else
|
88
|
-
id = resrc.is_a?(Integer) ? resrc : resrc
|
89
|
-
"#{
|
108
|
+
id = (resrc.is_a?(Integer) ? resrc : resrc.id).to_i
|
109
|
+
raise ArgumentError, "id must be an integer! was #{id.class}" unless id.is_a?(Integer)
|
110
|
+
"#{uri}/#{id}".freeze
|
90
111
|
end
|
91
112
|
end
|
113
|
+
|
114
|
+
UriHelperMethods.register "#{plural_name}_uri_template" do |collection = false|
|
115
|
+
(collection ? uri : "#{uri}/:id").freeze
|
116
|
+
end
|
92
117
|
end
|
93
118
|
|
94
119
|
def register_new_resource_uri
|
95
|
-
uri = "#{base}/#{plural_name}/form"
|
96
|
-
|
97
|
-
|
98
|
-
|
120
|
+
uri = "#{base}/#{plural_name}/form".freeze
|
121
|
+
|
122
|
+
UriHelperMethods.register("new_#{name}_uri") { uri }
|
123
|
+
UriHelperMethods.register("new_#{name}_uri_template") { uri }
|
99
124
|
end
|
100
125
|
|
101
126
|
def register_edit_resource_uri
|
102
127
|
uri = "#{base}/#{plural_name}"
|
128
|
+
|
103
129
|
UriHelperMethods.register "edit_#{name}_uri" do |resrc|
|
104
130
|
id = resrc.is_a?(Integer) ? resrc : resrc&.id
|
105
131
|
"#{uri}/#{id}/edit".freeze unless id.nil?
|
106
132
|
end
|
133
|
+
|
134
|
+
UriHelperMethods.register "edit_#{name}_uri_template" do
|
135
|
+
"#{uri}/:id/edit".freeze
|
136
|
+
end
|
107
137
|
end
|
108
138
|
end
|
109
139
|
|
@@ -113,6 +143,10 @@ module Shaf
|
|
113
143
|
"#{name}_uri"
|
114
144
|
end
|
115
145
|
|
146
|
+
def template_method_name(name)
|
147
|
+
"#{method_name(name)}_template"
|
148
|
+
end
|
149
|
+
|
116
150
|
def signature(name, uri)
|
117
151
|
args = extract_symbols(uri)
|
118
152
|
s = method_name(name)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Shaf
|
2
|
+
module SymbolicRoutes
|
3
|
+
[
|
4
|
+
:get,
|
5
|
+
:put,
|
6
|
+
:post,
|
7
|
+
:patch,
|
8
|
+
:delete,
|
9
|
+
:head,
|
10
|
+
:options,
|
11
|
+
:link,
|
12
|
+
:unlink
|
13
|
+
].each do |m|
|
14
|
+
define_method m do |path, &block|
|
15
|
+
super(rewrite_path(path), &block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def rewrite_path(path)
|
20
|
+
return path unless path.is_a? Symbol
|
21
|
+
|
22
|
+
m = "#{path}_template"
|
23
|
+
raise "Don't know how to 'get #{path}'" unless respond_to? m
|
24
|
+
send m
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/shaf/formable.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
module Shaf
|
2
2
|
module Formable
|
3
3
|
class Field
|
4
|
-
attr_reader :name, :type, :value, :label
|
4
|
+
attr_reader :name, :type, :value, :label, :required
|
5
|
+
|
6
|
+
HTML_TYPE_MAPPINGS = {
|
7
|
+
'string' => 'text',
|
8
|
+
'boolean' => 'checkbox',
|
9
|
+
}.freeze
|
5
10
|
|
6
11
|
def initialize(name, params = {})
|
7
12
|
@name = name
|
@@ -9,6 +14,7 @@ module Shaf
|
|
9
14
|
@label = params[:label]
|
10
15
|
@has_value = params.key? :value
|
11
16
|
@value = params[:value]
|
17
|
+
@required = params[:required] || false
|
12
18
|
end
|
13
19
|
|
14
20
|
def has_value?
|
@@ -32,8 +38,18 @@ module Shaf
|
|
32
38
|
end
|
33
39
|
|
34
40
|
def input_element
|
35
|
-
_value = value ? %Q(
|
36
|
-
|
41
|
+
_value = value ? %Q(value="#{value.to_s}") : nil
|
42
|
+
_required = required ? "required" : nil
|
43
|
+
attributes = [
|
44
|
+
%Q(type="#{HTML_TYPE_MAPPINGS[type.to_s]}"),
|
45
|
+
'class="form--input"',
|
46
|
+
%Q(id="#{name.to_s}"),
|
47
|
+
%Q(name="#{name.to_s}"),
|
48
|
+
]
|
49
|
+
attributes << %Q(value="#{value.to_s}") if value
|
50
|
+
attributes << "required" if required
|
51
|
+
|
52
|
+
"<input #{attributes.join(" ")}>"
|
37
53
|
end
|
38
54
|
end
|
39
55
|
|
@@ -2,52 +2,50 @@ require '<%= policy_file %>'
|
|
2
2
|
|
3
3
|
class <%= controller_class_name %> < BaseController
|
4
4
|
|
5
|
+
authorize_with <%= policy_class_name %>
|
6
|
+
|
5
7
|
resource_uris_for :<%= name %>
|
6
8
|
|
7
|
-
|
9
|
+
get :<%= plural_name %>_uri do
|
10
|
+
authorize! :read
|
11
|
+
collection = paginate(<%= model_class_name %>.order(:created_at).reverse)
|
12
|
+
respond_with_collection collection, serializer: <%= serializer_class_name %>
|
13
|
+
end
|
8
14
|
|
9
|
-
get
|
10
|
-
|
11
|
-
|
12
|
-
form.href = <%= plural_name %>_uri
|
13
|
-
respond_with form
|
15
|
+
get :new_<%= name %>_uri do
|
16
|
+
authorize! :read
|
17
|
+
respond_with create_form
|
14
18
|
end
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
respond_with
|
20
|
+
post :<%= plural_name %>_uri do
|
21
|
+
authorize! :write
|
22
|
+
<%= name %> = <%= model_class_name %>.create(<%= name %>_params)
|
23
|
+
headers({ "Location" => <%= name %>_uri(<%= name %>) })
|
24
|
+
respond_with <%= name %>, status: 201
|
21
25
|
end
|
22
26
|
|
23
|
-
get
|
27
|
+
get :<%= name %>_uri do
|
28
|
+
authorize! :read
|
24
29
|
respond_with <%= name %>
|
25
30
|
end
|
26
31
|
|
27
|
-
|
32
|
+
get :edit_<%= name %>_uri do
|
33
|
+
authorize! :read
|
34
|
+
respond_with edit_form
|
35
|
+
end
|
36
|
+
|
37
|
+
put :<%= name %>_uri do
|
28
38
|
authorize! :write
|
29
39
|
<%= name %>.update(<%= name %>_params)
|
30
40
|
respond_with <%= name %>
|
31
41
|
end
|
32
42
|
|
33
|
-
delete
|
43
|
+
delete :<%= name %>_uri do
|
34
44
|
authorize! :write
|
35
45
|
<%= name %>.destroy
|
36
46
|
status 204
|
37
47
|
end
|
38
48
|
|
39
|
-
get '/<%= plural_name %>' do
|
40
|
-
collection = paginate(<%= model_class_name %>.order(:created_at).reverse)
|
41
|
-
respond_with_collection collection, serializer: <%= serializer_class_name %>
|
42
|
-
end
|
43
|
-
|
44
|
-
post '/<%= plural_name %>' do
|
45
|
-
authorize! :write
|
46
|
-
<%= name %> = <%= model_class_name %>.create(<%= name %>_params)
|
47
|
-
headers({ "Location" => <%= name %>_uri(<%= name %>) })
|
48
|
-
respond_with <%= name %>, status: 201
|
49
|
-
end
|
50
|
-
|
51
49
|
def <%= name %>_params
|
52
50
|
# Generated method - TODO: Remove any params that should not be allowed!
|
53
51
|
safe_params(<%= params.map { |p| ":#{p[0]}" }.join(', ') %>)
|
@@ -59,4 +57,17 @@ class <%= controller_class_name %> < BaseController
|
|
59
57
|
end
|
60
58
|
end
|
61
59
|
|
60
|
+
def create_form
|
61
|
+
<%= model_class_name %>.create_form.tap do |form|
|
62
|
+
form.self_link = new_<%= name %>_uri
|
63
|
+
form.href = <%= plural_name %>_uri
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def edit_form
|
68
|
+
<%= name %>.edit_form.tap do |form|
|
69
|
+
form.self_link = edit_<%= name %>_uri(<%= name %>)
|
70
|
+
form.href = <%= name %>_uri(<%= name %>)
|
71
|
+
end
|
72
|
+
end
|
62
73
|
end
|
@@ -3,6 +3,8 @@ class <%= policy_class_name %>
|
|
3
3
|
|
4
4
|
# Auto generated policy: Update this file to suite your API!
|
5
5
|
|
6
|
+
alias :<%= name %> :resource
|
7
|
+
|
6
8
|
<%= attributes.join("\n ") %>
|
7
9
|
|
8
10
|
link :up
|
@@ -16,11 +18,12 @@ class <%= policy_class_name %>
|
|
16
18
|
end
|
17
19
|
|
18
20
|
def read?
|
21
|
+
# FIXME!!
|
19
22
|
true
|
20
23
|
end
|
21
24
|
|
22
25
|
def write?
|
23
|
-
# !!
|
26
|
+
# FIXME!!
|
24
27
|
true
|
25
28
|
end
|
26
29
|
end
|
data/lib/shaf/helpers.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'shaf/helpers/payload'
|
2
2
|
require 'shaf/helpers/json_html'
|
3
3
|
require 'shaf/helpers/paginate'
|
4
|
-
require 'shaf/helpers/session'
|
5
4
|
|
6
5
|
module Shaf
|
7
6
|
def self.helpers
|
@@ -9,7 +8,6 @@ module Shaf
|
|
9
8
|
Payload,
|
10
9
|
JsonHtml,
|
11
10
|
Paginate,
|
12
|
-
Session,
|
13
11
|
]
|
14
12
|
end
|
15
13
|
end
|
data/lib/shaf/helpers/payload.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Shaf
|
2
2
|
module Payload
|
3
|
+
EXCLUDED_FORM_PARAMS = ['captures', 'splat'].freeze
|
4
|
+
|
3
5
|
def supported_response_types(resource)
|
4
6
|
[
|
5
7
|
mime_type(:hal),
|
@@ -39,7 +41,7 @@ module Shaf
|
|
39
41
|
|
40
42
|
def parse_payload
|
41
43
|
if request.env['CONTENT_TYPE'] == 'application/x-www-form-urlencoded'
|
42
|
-
return params.reject { |key,_|
|
44
|
+
return params.reject { |key,_| EXCLUDED_FORM_PARAMS.include? key }
|
43
45
|
end
|
44
46
|
|
45
47
|
input = read_input
|
@@ -56,9 +58,11 @@ module Shaf
|
|
56
58
|
|
57
59
|
def safe_params(*fields)
|
58
60
|
return {} unless payload
|
61
|
+
field_strings = fields.map { |f| f.to_s.downcase }
|
62
|
+
field_strings << 'id' unless field_strings.include? 'id'
|
63
|
+
|
59
64
|
{}.tap do |allowed|
|
60
|
-
|
61
|
-
f = field.to_s.downcase
|
65
|
+
field_strings.each do |f|
|
62
66
|
allowed[f.to_sym] = payload[f] if payload[f]
|
63
67
|
end
|
64
68
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Shaf
|
2
2
|
module Spec
|
3
|
-
module
|
3
|
+
module HttpUtils
|
4
4
|
include ::Rack::Test::Methods
|
5
5
|
|
6
|
-
[:get, :put, :post, :delete].each do |m|
|
6
|
+
[:get, :put, :patch, :post, :delete, :options, :head, :link, :unlink].each do |m|
|
7
7
|
define_method m do |*args|
|
8
8
|
set_headers
|
9
9
|
super(*args)
|
@@ -16,9 +16,8 @@ module Shaf
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def headers
|
19
|
-
last_response&.headers
|
19
|
+
last_response&.headers || {}
|
20
20
|
end
|
21
|
-
|
22
21
|
end
|
23
22
|
end
|
24
23
|
end
|
@@ -2,7 +2,7 @@ module Shaf
|
|
2
2
|
module Spec
|
3
3
|
class IntegrationSpec < Minitest::Spec
|
4
4
|
include Minitest::Hooks
|
5
|
-
include
|
5
|
+
include HttpUtils
|
6
6
|
include PayloadUtils
|
7
7
|
include UriHelper
|
8
8
|
|
@@ -30,6 +30,8 @@ module Shaf
|
|
30
30
|
def parse_response(body)
|
31
31
|
return nil if body.empty?
|
32
32
|
JSON.parse(body, symbolize_names: true)
|
33
|
+
rescue JSON::ParserError => e
|
34
|
+
assert e.nil?, "Could not parse reponse as json"
|
33
35
|
end
|
34
36
|
|
35
37
|
def app
|
@@ -46,6 +48,13 @@ module Shaf
|
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
51
|
+
def auth_token(token)
|
52
|
+
@__integration_test_auth_token = token
|
53
|
+
end
|
54
|
+
|
55
|
+
def clear_auth_token
|
56
|
+
@__integration_test_auth_token = nil
|
57
|
+
end
|
49
58
|
|
50
59
|
# def login(email, pass)
|
51
60
|
# params = {email: email, password: pass}
|
@@ -3,42 +3,6 @@ require 'minitest/assertions'
|
|
3
3
|
module Shaf
|
4
4
|
module Spec
|
5
5
|
module PayloadUtils
|
6
|
-
|
7
|
-
class Embedded
|
8
|
-
include HttpMethodUtils
|
9
|
-
include PayloadUtils
|
10
|
-
include Minitest::Assertions
|
11
|
-
|
12
|
-
# This is needed by Minitest::Assertions
|
13
|
-
# And we need that module to have all assert_*/refute_* methods
|
14
|
-
# available in this class
|
15
|
-
attr_accessor :assertions
|
16
|
-
|
17
|
-
def initialize(payload, context, block)
|
18
|
-
@payload = payload
|
19
|
-
@context = context
|
20
|
-
@block = block
|
21
|
-
@assertions = 0
|
22
|
-
end
|
23
|
-
|
24
|
-
def call(*args)
|
25
|
-
instance_exec(*args, &@block)
|
26
|
-
end
|
27
|
-
|
28
|
-
def method_missing(method, *args, &block)
|
29
|
-
if @context&.respond_to? method
|
30
|
-
define_singleton_method(method) { |*a, &b| @context.public_send(method, *a, &b) }
|
31
|
-
return public_send(method, *args, &block)
|
32
|
-
end
|
33
|
-
super
|
34
|
-
end
|
35
|
-
|
36
|
-
def respond_to_missing?(method, include_private = false)
|
37
|
-
return true if @context&.respond_to? method
|
38
|
-
super
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
6
|
def set_payload(payload)
|
43
7
|
@payload = payload
|
44
8
|
@payload = JSON.parse(payload, symbolize_names: true) if payload.is_a?(String)
|
@@ -69,7 +33,7 @@ module Shaf
|
|
69
33
|
assert_has_embedded name unless name.nil?
|
70
34
|
keys = [:_embedded, name&.to_sym].compact
|
71
35
|
return last_payload.dig(*keys) unless block_given?
|
72
|
-
|
36
|
+
exec_embed_block(last_payload.dig(*keys), Proc.new)
|
73
37
|
end
|
74
38
|
|
75
39
|
def each_embedded(name, &block)
|
@@ -80,7 +44,7 @@ module Shaf
|
|
80
44
|
"Embedded '#{name}' is not an instance of Array. Actual: #{list.class}"
|
81
45
|
|
82
46
|
list.each_with_index do |resource, i|
|
83
|
-
|
47
|
+
exec_embed_block(resource, block, i)
|
84
48
|
end
|
85
49
|
end
|
86
50
|
|
@@ -172,6 +136,15 @@ module Shaf
|
|
172
136
|
"Response contains disallowed embedded resource with name '#{name}': #{last_payload}"
|
173
137
|
end
|
174
138
|
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def exec_embed_block(payload, block, *args)
|
143
|
+
prev_payload = last_payload
|
144
|
+
set_payload(payload)
|
145
|
+
instance_exec(*args, &block)
|
146
|
+
set_payload(prev_payload)
|
147
|
+
end
|
175
148
|
end
|
176
149
|
end
|
177
150
|
end
|
data/lib/shaf/tasks/test.rb
CHANGED
@@ -5,24 +5,28 @@ namespace :test do |ns|
|
|
5
5
|
t.libs = %w(. api spec)
|
6
6
|
t.pattern = "spec/integration/**/*_spec.rb"
|
7
7
|
t.verbose = true
|
8
|
+
t.warning = false
|
8
9
|
end
|
9
10
|
|
10
11
|
Rake::TestTask.new(:models) do |t|
|
11
12
|
t.libs = %w(. api spec)
|
12
13
|
t.pattern = "spec/models/**/*_spec.rb"
|
13
14
|
t.verbose = true
|
15
|
+
t.warning = false
|
14
16
|
end
|
15
17
|
|
16
18
|
Rake::TestTask.new(:serializers) do |t|
|
17
19
|
t.libs = %w(. api spec)
|
18
20
|
t.pattern = "spec/serializers/**/*_spec.rb"
|
19
21
|
t.verbose = true
|
22
|
+
t.warning = false
|
20
23
|
end
|
21
24
|
|
22
25
|
Rake::TestTask.new(:lib) do |t|
|
23
26
|
t.libs = %w(. api spec)
|
24
27
|
t.pattern = "spec/lib/**/*_spec.rb"
|
25
28
|
t.verbose = true
|
29
|
+
t.warning = false
|
26
30
|
end
|
27
31
|
|
28
32
|
Rake::TestTask.new(:all) do |t|
|
@@ -34,6 +38,7 @@ namespace :test do |ns|
|
|
34
38
|
"spec/integration/**/*_spec.rb"
|
35
39
|
]
|
36
40
|
t.verbose = true
|
41
|
+
t.warning = false
|
37
42
|
end
|
38
43
|
|
39
44
|
end
|
data/lib/shaf/version.rb
CHANGED
@@ -12,21 +12,28 @@ class BaseController < Sinatra::Base
|
|
12
12
|
set :public_folder, ASSETS_DIR
|
13
13
|
disable :dump_errors
|
14
14
|
set :show_exceptions, :after_handler
|
15
|
+
enable :current_user
|
16
|
+
set :auth_token_header, AUTH_TOKEN_HEADER
|
15
17
|
end
|
16
18
|
|
17
19
|
use Rack::Deflater
|
18
|
-
register(*Shaf.extensions)
|
19
|
-
helpers(*Shaf.helpers)
|
20
20
|
|
21
21
|
def self.inherited(controller)
|
22
22
|
super
|
23
23
|
Shaf::App.use controller
|
24
24
|
end
|
25
25
|
|
26
|
-
def log
|
26
|
+
def self.log
|
27
27
|
$logger
|
28
28
|
end
|
29
29
|
|
30
|
+
def log
|
31
|
+
self.class.log
|
32
|
+
end
|
33
|
+
|
34
|
+
register(*Shaf.extensions)
|
35
|
+
helpers(*Shaf.helpers)
|
36
|
+
|
30
37
|
before do
|
31
38
|
log.info "Processing: #{request.request_method} #{request.path_info}"
|
32
39
|
log.debug "Payload: #{payload || 'empty'}"
|
@@ -1,12 +1,13 @@
|
|
1
1
|
class DocsController < BaseController
|
2
2
|
|
3
|
-
register_uri :doc_curie,
|
3
|
+
register_uri :doc_curie, '/doc/:resource/rels/{rel}'
|
4
|
+
register_uri :documentation, '/doc/:resource'
|
4
5
|
|
5
|
-
get
|
6
|
+
get doc_curie_uri_template do
|
6
7
|
doc.link(params[:rel])
|
7
8
|
end
|
8
9
|
|
9
|
-
get
|
10
|
+
get documentation_uri_template do
|
10
11
|
doc.to_s
|
11
12
|
end
|
12
13
|
|
@@ -33,9 +33,13 @@ class FormSerializer
|
|
33
33
|
fields = resource&.fields
|
34
34
|
break if fields.nil? || fields.empty?
|
35
35
|
hash[:fields] = fields.map do |field|
|
36
|
-
{
|
36
|
+
{
|
37
|
+
name: field.name,
|
38
|
+
type: field.type,
|
39
|
+
label: field.label,
|
40
|
+
}.tap do |f|
|
37
41
|
f[:value] = field.value if field.has_value?
|
38
|
-
f[:
|
42
|
+
f[:required] = true if field.required
|
39
43
|
end
|
40
44
|
end
|
41
45
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
APP_ROOT = File.expand_path('../', __dir__)
|
2
2
|
APP_DIR = File.expand_path('api', APP_ROOT)
|
3
|
+
SRC_DIR = File.expand_path('src', APP_ROOT)
|
3
4
|
VIEWS_DIR = File.join(APP_ROOT, Shaf::Settings.views_folder)
|
4
5
|
ASSETS_DIR = File.join(APP_ROOT, Shaf::Settings.public_folder)
|
6
|
+
AUTH_TOKEN_HEADER = 'HTTP_X_AUTH_TOKEN'
|
5
7
|
PAGINATION_PER_PAGE = Shaf::Settings.paginate_per_page || 25
|
@@ -21,7 +21,7 @@ def sort_files(files)
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
|
24
|
+
def require_ruby_files
|
25
25
|
files = Dir[File.join('**', '*.rb')]
|
26
26
|
sort_files(files).each do |file|
|
27
27
|
# load all files with .rb extension in subfolders of api
|
@@ -30,3 +30,15 @@ Dir.chdir(APP_DIR) do
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
if Dir.exist? SRC_DIR
|
34
|
+
$:.unshift SRC_DIR
|
35
|
+
|
36
|
+
Dir.chdir(SRC_DIR) do
|
37
|
+
require_ruby_files
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
Dir.chdir(APP_DIR) do
|
42
|
+
require_ruby_files
|
43
|
+
end
|
44
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shaf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sammy Henningsson
|
@@ -31,7 +31,7 @@ cert_chain:
|
|
31
31
|
CNZdF8Vavp6xMQbPHZwqjaeZz2WRXYS7jyYSvCunjwa3OtvXtfbIEGEWE6IM+t9k
|
32
32
|
H1g6Q+B6qk9O6g==
|
33
33
|
-----END CERTIFICATE-----
|
34
|
-
date: 2018-03-
|
34
|
+
date: 2018-03-26 00:00:00.000000000 Z
|
35
35
|
dependencies:
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rake
|
@@ -252,7 +252,9 @@ files:
|
|
252
252
|
- lib/shaf/errors.rb
|
253
253
|
- lib/shaf/extensions.rb
|
254
254
|
- lib/shaf/extensions/authorize.rb
|
255
|
+
- lib/shaf/extensions/current_user.rb
|
255
256
|
- lib/shaf/extensions/resource_uris.rb
|
257
|
+
- lib/shaf/extensions/symbolic_routes.rb
|
256
258
|
- lib/shaf/formable.rb
|
257
259
|
- lib/shaf/generator.rb
|
258
260
|
- lib/shaf/generator/controller.rb
|
@@ -277,7 +279,6 @@ files:
|
|
277
279
|
- lib/shaf/helpers/json_html.rb
|
278
280
|
- lib/shaf/helpers/paginate.rb
|
279
281
|
- lib/shaf/helpers/payload.rb
|
280
|
-
- lib/shaf/helpers/session.rb
|
281
282
|
- lib/shaf/middleware.rb
|
282
283
|
- lib/shaf/middleware/request_id.rb
|
283
284
|
- lib/shaf/registrable_factory.rb
|
metadata.gz.sig
CHANGED
Binary file
|
data/lib/shaf/helpers/session.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'digest'
|
2
|
-
|
3
|
-
module Shaf
|
4
|
-
module Session
|
5
|
-
|
6
|
-
SESSION_TTL = 60 * 60 * 24 * 2 # 2 days
|
7
|
-
|
8
|
-
def login(email, password)
|
9
|
-
return unless email && password
|
10
|
-
user = User.first(email: email) or return
|
11
|
-
bcrypt = BCrypt::Password.new(user.password_digest)
|
12
|
-
return unless bcrypt == password
|
13
|
-
@current_user = user
|
14
|
-
|
15
|
-
Session.where(user_id: user.id).delete
|
16
|
-
params = {
|
17
|
-
user_id: user.id,
|
18
|
-
expire_at: Time.now + SESSION_TTL,
|
19
|
-
}
|
20
|
-
Session.create(params)
|
21
|
-
end
|
22
|
-
|
23
|
-
def extend_session(session)
|
24
|
-
return unless session
|
25
|
-
session.update(expire_at: Time.now + SESSION_TTL)
|
26
|
-
session.auth_token = request.env['HTTP_X_AUTH_TOKEN']
|
27
|
-
session
|
28
|
-
end
|
29
|
-
|
30
|
-
def logout
|
31
|
-
current_session&.destroy
|
32
|
-
end
|
33
|
-
|
34
|
-
def current_user
|
35
|
-
unless defined?(@current_user) && @current_user
|
36
|
-
return unless request.env.key? 'HTTP_X_AUTH_TOKEN'
|
37
|
-
digest = Digest::SHA256.hexdigest(request.env['HTTP_X_AUTH_TOKEN'])
|
38
|
-
session = Session.where(auth_token_digest: digest).first
|
39
|
-
@current_user = User[session.user_id] if session&.valid?
|
40
|
-
end
|
41
|
-
@current_user
|
42
|
-
end
|
43
|
-
|
44
|
-
def current_session
|
45
|
-
unless @current_session
|
46
|
-
return unless current_user
|
47
|
-
@current_session = Session.where(user_id: current_user.id).first
|
48
|
-
end
|
49
|
-
@current_session
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
53
|
-
end
|