shaf 0.2.1 → 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
  SHA256:
3
- metadata.gz: a160e3aeb1d9b86b59371417e6354d351acfbe9a90efde270b51a1fe2a307a88
4
- data.tar.gz: d3c9eec43a5b5da8795e1e9396f8916be2458d235a14296c75646be25680b658
3
+ metadata.gz: 45e90f32663688a63993bcf1aa79c6c9b8667d11dbfc9a5fdba50141e983ea53
4
+ data.tar.gz: 919292b331cc09ce95031e4d1e723371114fef9e86b6d97c2e90e816befb0d77
5
5
  SHA512:
6
- metadata.gz: '093623e69f3fdf57124cdabd6b01c00129fe77e479ec54aa5d3fdef252ec92fa93895b99708ca7c831421c11c838dbe9e034acec9546c96fc1a5f6197bd39211'
7
- data.tar.gz: 4305a775fff58412125a1c984d27617c87fdd3d0fa1f20b798f6b47978aeafb34996bcd8f67b97f6ac1e3e1a2f117bf55c33f4e615af10bc0fdf917d61730231
6
+ metadata.gz: 788b01fd3f933f9e86ef99c9b51c14768208f73c5dc3cf4fe0a39fcb19078f82eb7eaaa2a1dcfc33d4d1a44980dc66254693a240b2e2b28d4a6e6b0d0383b676
7
+ data.tar.gz: a07510311e28e5008991d5461f9c2e97485640cd146a8304874bc216888eb722c941c266dc74b59b184ca3ea302b6a508a315421ed040dd64c2d111ea80548c7
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -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
@@ -19,7 +19,7 @@ module Shaf
19
19
 
20
20
  module Helpers
21
21
  def policy(resource)
22
- return @policy if @policy
22
+ return @policy if defined?(@policy) && @policy
23
23
  user = current_user if respond_to? :current_user
24
24
  @policy = self.class.policy_class&.new(user, resource)
25
25
  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
- include UriHelper
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
- UriHelperMethods.register "#{plural_name}_uri" do
67
- uri.dup.freeze
68
- end
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
- "#{uri}/#{id}".freeze unless id.nil?
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.dup.freeze
106
+ uri.freeze
87
107
  else
88
- id = resrc.is_a?(Integer) ? resrc : resrc&.id
89
- "#{uri}/#{id}".freeze unless id.nil?
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
- UriHelperMethods.register "new_#{name}_uri" do
97
- uri.dup.freeze
98
- end
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
@@ -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( value="#{value.to_s}") : ""
36
- %Q(<input type="#{type.to_s}" class="form--input" id="#{name.to_s}" name="#{name.to_s}"#{_value}>)
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
 
@@ -35,6 +35,7 @@ module Shaf
35
35
  def opts
36
36
  {
37
37
  policy_class_name: "#{policy_name.capitalize}Policy",
38
+ name: policy_name,
38
39
  attributes: attributes,
39
40
  }
40
41
  end
@@ -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
- authorize_with <%= policy_class_name %>
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 '/<%= plural_name %>/form' do
10
- form = <%= model_class_name %>.create_form
11
- form.self_link = new_<%= name %>_uri
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
- get '/<%= plural_name %>/:id/edit' do
17
- form = <%= name %>.edit_form
18
- form.self_link = edit_<%= name %>_uri(<%= name %>)
19
- form.href = <%= name %>_uri(<%= name %>)
20
- respond_with form
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 '/<%= plural_name %>/:id' do
27
+ get :<%= name %>_uri do
28
+ authorize! :read
24
29
  respond_with <%= name %>
25
30
  end
26
31
 
27
- put '/<%= plural_name %>/:id' do
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 '/<%= plural_name %>/:id' do
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
- # !!current_user
26
+ # FIXME!!
24
27
  true
25
28
  end
26
29
  end
@@ -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
@@ -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,_| ['captures', 'splat'].include? 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
- fields.each do |field|
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 HttpMethodUtils
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 HttpMethodUtils
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
- Embedded.new(last_payload.dig(*keys), self, Proc.new).call
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
- Embedded.new(resource, self, block).call(i)
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Shaf
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -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, '/doc/:resource/rels/{rel}'
3
+ register_uri :doc_curie, '/doc/:resource/rels/{rel}'
4
+ register_uri :documentation, '/doc/:resource'
4
5
 
5
- get '/doc/:resource/rels/:rel' do
6
+ get doc_curie_uri_template do
6
7
  doc.link(params[:rel])
7
8
  end
8
9
 
9
- get '/doc/:resource' do
10
+ get documentation_uri_template do
10
11
  doc.to_s
11
12
  end
12
13
 
@@ -2,7 +2,7 @@ class RootController < BaseController
2
2
 
3
3
  register_uri :root, '/'
4
4
 
5
- get '/' do
5
+ get root_uri do
6
6
  respond_with nil, serializer: RootSerializer
7
7
  end
8
8
  end
@@ -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
- { name: field.name, type: field.type }.tap do |f|
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[:label] = field.label
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
- Dir.chdir(APP_DIR) do
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.2.1
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-14 00:00:00.000000000 Z
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
@@ -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