app_rail-airtable 0.2.12 → 0.3.2

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: 3093a14dafa5e25f4cc4a7791bedfc00f1c2f5941f99c6a07060ea60e12e7ff8
4
- data.tar.gz: bd3ece807677d1ffa0d29f92b254fd484ad10b0ab7ca16312b31126c3d96bd1a
3
+ metadata.gz: 98fa16c4b212cd84ea0d9cd5caa37100c3f3bf9d97919cb1814d914d45fdf2c6
4
+ data.tar.gz: d16166e491328eaa897086cd43940e11b52e8345bfd8bef3bcb547537304e2cd
5
5
  SHA512:
6
- metadata.gz: 5e79328b4a2eca0a521541ebc8164b91374263fc3f6e6f91d2d847774a65baabfad66bec4b4672484a8eedb8da060f6c5fc19f909537d8076e18a75b31c94384
7
- data.tar.gz: a0eb587cb217d6c336d9cbe8fd52f72eb41dc24e582c58877ba72d5dd7ec2b034a0711ac782a00e29dcfdea944cb531e65f532b031e5fcf1de0c25827016e99a
6
+ metadata.gz: 2532b3183fba2e26b117e232a54d65120f9e08a874d46a1a08e6331bc11ee10de6a8460622d68c7bc46ec633090beb023d7de7b4a34dc2546c6013469b2157d6
7
+ data.tar.gz: ae372f1540f615fffd90045c6e2c6b4f1e4252278dcb256d4262d04a6356b50e1510676ed94f6d0358c4608f967caec00214fa6df4ebb6b9334f41846ec5a85d
data/.gitignore CHANGED
@@ -1,3 +1,7 @@
1
+ .DS_STORE
2
+ *.swp
3
+ *.rbc
4
+ *.sass-cache
1
5
  /.bundle/
2
6
  /.yardoc
3
7
  /_yardoc/
@@ -10,3 +14,6 @@
10
14
  # rspec failure tracking
11
15
  .rspec_status
12
16
  .byebug_history
17
+
18
+ # dotenv
19
+ .env
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- app_rail-airtable (0.2.12)
4
+ app_rail-airtable (0.3.2)
5
5
  activesupport
6
6
  airrecord
7
7
  bcrypt
data/README.md CHANGED
@@ -36,7 +36,18 @@ To provide support for routes, models can implement
36
36
  In order to support authentication you should create a class (normally `User`) and inherit from `AppRail::Airtable::AuthenticationRecord`. Your table needs `Email`, `Password Hash` and `Access Token` columns.
37
37
 
38
38
  ### Servers
39
- You should create a single server which extends `AppRail::Airtable::Sinatra`, then add routes with the `resources` macro to add `index`, `show` and `create` routes. You can also provide your own routes.
39
+ You should create a single server which extends `AppRail::Airtable::Sinatra`.
40
+
41
+ App Rail Airtable provides two helpers to generate routes
42
+
43
+ **resources(name, only:)**
44
+ Creates routes that map to a table. It delegates from the route to a model method
45
+ * `index` to `ar_list_item`
46
+ * `show` to `ar_stack`
47
+ * `create` to `self.create_as_json`
48
+
49
+ **authenticable_resources(name, , only:)**
50
+ Acts as `resources` but also takes a block of routes. Those nested routes will all call the `authenticate!` helper method before running. The `authenticate!` helper will call a lookup helper `find_authenticatable_resource(access_token:)` with the bearer token found in the `HTTP_AUTHORIZATION` header, which should be used to look up the correct object or return nil if none is found (resulting in a 401 response).
40
51
 
41
52
  ## License
42
53
 
@@ -17,6 +17,7 @@ module AppRail
17
17
  def self.airtable_attr(*attributes)
18
18
  attributes.each do |attribute|
19
19
  define_method(attribute.to_s.snake_case) { self[attribute] }
20
+ define_method("#{attribute.to_s.snake_case}=") { |value| self[attribute] = value }
20
21
  end
21
22
  end
22
23
 
@@ -12,19 +12,21 @@ module AppRail
12
12
 
13
13
  module ClassMethods
14
14
  def create(email:, password:)
15
- user = User.new("Email" => email, "Password Hash" => password_hash(password), "Access Token" => access_token)
15
+ user = User.new("Email" => email, "Password Hash" => password_hash(password), "Access Token" => next_access_token)
16
16
  user.create
17
17
  user
18
18
  end
19
19
 
20
20
  def create_session_as_json(email:, password:)
21
21
  user = find_by_email_and_password(email, password)
22
+ user["Access Token"] = next_access_token
23
+ user.save
22
24
  user&.oauth_session
23
25
  end
24
26
 
25
27
  def find_by_email_and_password(email, password)
26
28
  user = all(filter: "{Email} = \"#{email}\"").first
27
- user.valid_password? ? user : nil
29
+ user.valid_password?(password) ? user : nil
28
30
  end
29
31
 
30
32
  def find_by_access_token(access_token)
@@ -35,7 +37,7 @@ module AppRail
35
37
  BCrypt::Password.create(password)
36
38
  end
37
39
 
38
- def access_token
40
+ def next_access_token
39
41
  SecureRandom.hex
40
42
  end
41
43
  end
@@ -6,7 +6,7 @@ module AppRail
6
6
  end
7
7
 
8
8
  def find_current_user
9
- authorization_header && bearer_token ? User.find_by_access_token(bearer_token) : nil
9
+ authorization_header && bearer_token ? find_authenticatable_resource(access_token: bearer_token) : nil
10
10
  end
11
11
 
12
12
  def bearer_token
@@ -24,6 +24,7 @@ end
24
24
  module AppRail
25
25
  module Airtable
26
26
  class Sinatra < Sinatra::Base
27
+ @@authenticated_route = false
27
28
 
28
29
  helpers do
29
30
  def request_body_as_json
@@ -35,36 +36,54 @@ module AppRail
35
36
  request_body_as_json.merge(params)
36
37
  end
37
38
  end
39
+
40
+ def self.authenticatable_resources(name, only: [:index, :show, :create])
41
+
42
+ # If authentication is used then include the correct helpers
43
+ # Allowing the routes to use `authenticate!` and `current_user`
44
+ helpers AppRail::Airtable::AuthenticationHelpers
45
+
46
+ resources(name, only: only)
47
+
48
+ return unless block_given?
49
+ @@authenticated_route = true
50
+ yield
51
+ @@authenticated_route = false
52
+ end
38
53
 
39
- def self.resources(name, only: [:index, :show, :create], authenticated: false)
54
+ def self.resources(name, only: [:index, :show, :create])
40
55
  only = [only] if only.is_a?(Symbol)
41
56
 
42
- index_route(name, authenticated) if only.include?(:index)
43
- show_route(name, authenticated) if only.include?(:show)
44
- create_route(name, authenticated) if only.include?(:create)
57
+ index_route(name, authenticated_route?) if only.include?(:index)
58
+ show_route(name, authenticated_route?) if only.include?(:show)
59
+ create_route(name, authenticated_route?) if only.include?(:create)
45
60
  end
46
61
 
47
- def self.index_route(name, authenticated)
62
+ def self.index_route(name, authenticated_route)
48
63
  get "/#{name.to_s}" do
49
- authenticate! if authenticated
50
- name.classify_constantize.index(user: authenticated ? current_user : nil).map(&:ar_list_item_as_json).to_json
64
+ authenticate! if authenticated_route
65
+ name.classify_constantize.index(user: authenticated_route ? current_user : nil).map(&:ar_list_item_as_json).to_json
51
66
  end
52
67
  end
53
68
 
54
- def self.show_route(name, authenticated)
69
+ def self.show_route(name, authenticated_route)
55
70
  get "/#{name.to_s}/:id" do
56
- authenticate! if authenticated
71
+ authenticate! if authenticated_route
57
72
  name.classify_constantize.find(params['id']).ar_stack_as_json.to_json
58
73
  end
59
74
  end
60
75
 
61
- def self.create_route(name, authenticated)
76
+ def self.create_route(name, authenticated_route)
62
77
  post "/#{name.to_s}" do
63
- authenticate! if authenticated
64
- as_json = name.classify_constantize.create_as_json(current_user: authenticated ? current_user : nil, params: params_and_body_as_json)
78
+ authenticate! if authenticated_route
79
+ as_json = name.classify_constantize.create_as_json(current_user: authenticated_route ? current_user : nil, params: params_and_body_as_json)
65
80
  [201, as_json.to_json]
66
81
  end
67
82
  end
83
+
84
+ def self.authenticated_route?
85
+ @@authenticated_route
86
+ end
68
87
  end
69
88
  end
70
89
  end
@@ -1,5 +1,5 @@
1
1
  module AppRail
2
2
  module Airtable
3
- VERSION = "0.2.12"
3
+ VERSION = "0.3.2"
4
4
  end
5
5
  end
@@ -2,7 +2,18 @@
2
2
  *.swp
3
3
  *.rbc
4
4
  *.sass-cache
5
- /pkg
6
- /coverage
7
- .yardoc
8
- /doc
5
+ /.bundle/
6
+ /.yardoc
7
+ /_yardoc/
8
+ /coverage/
9
+ /doc/
10
+ /pkg/
11
+ /spec/reports/
12
+ /tmp/
13
+
14
+ # rspec failure tracking
15
+ .rspec_status
16
+ .byebug_history
17
+
18
+ # dotenv
19
+ .env
@@ -7,9 +7,15 @@ ruby '2.7.4'
7
7
 
8
8
  gem 'app_rail-airtable'
9
9
 
10
- # dev
11
- gem 'dotenv'
10
+ group :development do
11
+ gem 'dotenv'
12
+ end
12
13
 
13
- # test
14
- gem "rspec"
15
- gem "rack-test"
14
+ group :test do
15
+ gem "rspec"
16
+ gem "rack-test"
17
+ end
18
+
19
+ group :development, :test do
20
+ gem 'byebug'
21
+ end
@@ -1,5 +1,11 @@
1
1
  $stdout.sync = true
2
2
 
3
- require 'dotenv/load'
3
+ ENV['RACK_ENV'] ||= 'development'
4
+ require 'dotenv/load' if ENV['RACK_ENV'] == 'development'
5
+ require 'bundler'
6
+ Bundler.require(:default, ENV['RACK_ENV'].to_sym)
7
+
8
+ require 'dotenv/load' if ENV['RACK_ENV'] == 'development'
9
+
4
10
  require './lib/server'
5
11
  run Server
@@ -23,7 +23,6 @@ require "rack/test"
23
23
  require "app_rail/airtable"
24
24
 
25
25
  require './lib/server'
26
- require './lib/item_recommender'
27
26
 
28
27
  RSpec.configure do |config|
29
28
  # rspec-expectations config goes here. You can use an alternate
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: app_rail-airtable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.12
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Brooke-Smith
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-06 00:00:00.000000000 Z
11
+ date: 2021-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport