app_rail-airtable 0.1.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f9ec1d3dd50d2b81b46a1f6804319b97424192accf1e825830ade564c4901aa5
4
- data.tar.gz: '0220939ea9dfd1ca57806f60328ca0bd4ea09417fdc2aeb1b61e70687024aeef'
3
+ metadata.gz: 208213f6a53029eb29b4d98ed9b6d4f9bb7bb0375d3a5de3866615c8701ec3d9
4
+ data.tar.gz: 5aea3eda06422225f87170aa3b1d8a8a3310123fb151a554b29ad8059db72847
5
5
  SHA512:
6
- metadata.gz: d13146f0116ea27771ac901dcc514938fa5e3b23e1b1342f6123a76a7e39bdb3b1dd1c7a2ce1bd477cc2a579a7c313ed44e521652f99ca9e8dcb78dba6b7a364
7
- data.tar.gz: e6cfc76d2a99c122d3643dd587bdef60a5e7131f04c4f7d0de0ed60ed76c2c130f6ded6d74123864fa6cb45c15cb904e0c7fcd2e4500720ce2479f4de6ae3132
6
+ metadata.gz: 975099138a2b7aef7ae085a09d7ace624f6b7eba9c892691807505ec44f8322dbf8b3a474113ecb3053b6d8243264db97531607ec2cfc3b4ad8907c253242dc0
7
+ data.tar.gz: 2b07588a9c2c375a0b4574a4500921c40f306c45bf153fd530520b7874716f4fbdb3b4cd56ade60c5dba9827b097052833e8827b4b564a83303af47bb4373af7
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/
@@ -9,3 +13,7 @@
9
13
 
10
14
  # rspec failure tracking
11
15
  .rspec_status
16
+ .byebug_history
17
+
18
+ # dotenv
19
+ .env
data/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # 0.4.6
2
+ * Add authenticatable_resource POST / DELETE `/<resource>/session` routes for sign in and sign out
3
+ * Simplify sign in methods & remove Authenticatable#create_session_as_json
4
+
5
+ # 0.4.0
6
+
7
+ ### Breaking changes
8
+ * `AppRail::Airtable::Sinatra` `.resources` and `.authenticable_resources` `only` argument defaults to `[:index, :show, :create, :update]` instead of `[:index, :show, :create]`
9
+
10
+ ### New features
11
+ * Add `Authenticatable#initialize` method to initialize an Airrecord record without persisting it to airtable
12
+ * Add `update` route (`PUT`), which points to the corresponding model method `self.update_as_json`
13
+
data/Gemfile CHANGED
@@ -1,7 +1,11 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in app_rail-airtable.gemspec
4
6
  gemspec
5
7
 
6
- gem "rake", "~> 12.0"
7
- gem "rspec", "~> 3.0"
8
+ gem 'byebug'
9
+ gem 'rake', '~> 12.0'
10
+ gem 'rspec', '~> 3.0'
11
+ gem 'thor'
data/Gemfile.lock CHANGED
@@ -1,55 +1,50 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- app_rail-airtable (0.1.0)
4
+ app_rail-airtable (0.5.0)
5
5
  activesupport
6
6
  airrecord
7
+ app_rail-steps
8
+ bcrypt
9
+ faraday (~> 2.2)
10
+ faraday-net_http_persistent (~> 2.0)
7
11
  sinatra
12
+ thor
8
13
 
9
14
  GEM
10
15
  remote: https://rubygems.org/
11
16
  specs:
12
- activesupport (6.1.4.1)
17
+ activesupport (7.0.4)
13
18
  concurrent-ruby (~> 1.0, >= 1.0.2)
14
19
  i18n (>= 1.6, < 2)
15
20
  minitest (>= 5.1)
16
21
  tzinfo (~> 2.0)
17
- zeitwerk (~> 2.3)
18
- airrecord (1.0.7)
19
- faraday (>= 0.10, < 2.0)
22
+ airrecord (1.0.10)
23
+ faraday (>= 1.0, < 3.0)
24
+ faraday-net_http_persistent
20
25
  net-http-persistent
21
- concurrent-ruby (1.1.9)
22
- connection_pool (2.2.5)
26
+ app_rail-steps (0.2.17)
27
+ bcrypt (3.1.18)
28
+ byebug (11.1.3)
29
+ concurrent-ruby (1.1.10)
30
+ connection_pool (2.3.0)
23
31
  diff-lcs (1.4.4)
24
- faraday (1.7.2)
25
- faraday-em_http (~> 1.0)
26
- faraday-em_synchrony (~> 1.0)
27
- faraday-excon (~> 1.1)
28
- faraday-httpclient (~> 1.0.1)
29
- faraday-net_http (~> 1.0)
30
- faraday-net_http_persistent (~> 1.1)
31
- faraday-patron (~> 1.0)
32
- faraday-rack (~> 1.0)
33
- multipart-post (>= 1.2, < 3)
32
+ faraday (2.6.0)
33
+ faraday-net_http (>= 2.0, < 3.1)
34
34
  ruby2_keywords (>= 0.0.4)
35
- faraday-em_http (1.0.0)
36
- faraday-em_synchrony (1.0.0)
37
- faraday-excon (1.1.0)
38
- faraday-httpclient (1.0.1)
39
- faraday-net_http (1.0.1)
40
- faraday-net_http_persistent (1.2.0)
41
- faraday-patron (1.0.0)
42
- faraday-rack (1.0.0)
43
- i18n (1.8.10)
35
+ faraday-net_http (3.0.1)
36
+ faraday-net_http_persistent (2.1.0)
37
+ faraday (~> 2.5)
38
+ net-http-persistent (~> 4.0)
39
+ i18n (1.12.0)
44
40
  concurrent-ruby (~> 1.0)
45
- minitest (5.14.4)
46
- multipart-post (2.1.1)
47
- mustermann (1.1.1)
41
+ minitest (5.16.3)
42
+ mustermann (2.0.2)
48
43
  ruby2_keywords (~> 0.0.1)
49
44
  net-http-persistent (4.0.1)
50
45
  connection_pool (~> 2.2)
51
46
  rack (2.2.3)
52
- rack-protection (2.1.0)
47
+ rack-protection (2.2.2)
53
48
  rack
54
49
  rack-test (1.1.0)
55
50
  rack (>= 1.0, < 3)
@@ -68,24 +63,26 @@ GEM
68
63
  rspec-support (~> 3.10.0)
69
64
  rspec-support (3.10.2)
70
65
  ruby2_keywords (0.0.5)
71
- sinatra (2.1.0)
72
- mustermann (~> 1.0)
66
+ sinatra (2.2.2)
67
+ mustermann (~> 2.0)
73
68
  rack (~> 2.2)
74
- rack-protection (= 2.1.0)
69
+ rack-protection (= 2.2.2)
75
70
  tilt (~> 2.0)
76
- tilt (2.0.10)
77
- tzinfo (2.0.4)
71
+ thor (1.1.0)
72
+ tilt (2.0.11)
73
+ tzinfo (2.0.5)
78
74
  concurrent-ruby (~> 1.0)
79
- zeitwerk (2.4.2)
80
75
 
81
76
  PLATFORMS
82
77
  ruby
83
78
 
84
79
  DEPENDENCIES
85
80
  app_rail-airtable!
81
+ byebug
86
82
  rack-test
87
83
  rake (~> 12.0)
88
84
  rspec (~> 3.0)
85
+ thor
89
86
 
90
87
  BUNDLED WITH
91
88
  2.1.4
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
- # AppRail::Airtable
1
+ # App Rail Airtable
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/app_rail/airtable`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ App Rail Airtable is a micro-framework based on Sinatra and [Airrecord](https://github.com/sirupsen/airrecord) which faciliates use of Airtable as a backend for App Rail Apps. You can deploy a template repo to Heroku for fast start.
6
4
 
7
5
  ## Installation
8
6
 
@@ -12,29 +10,79 @@ Add this line to your application's Gemfile:
12
10
  gem 'app_rail-airtable'
13
11
  ```
14
12
 
15
- And then execute:
13
+ ## Usage
16
14
 
17
- $ bundle install
15
+ App Rail Airtable has two important concepts, models and servers.
18
16
 
19
- Or install it yourself as:
17
+ ### Models
18
+ App Rail Airtable makes the following assumptions
19
+ 1. Your App will connect to a single Airtable Base
20
+ 2. Your Airtable Base implements a normalised datamodel
21
+ 3. Your tables in Airtable are plural versions of the models you create in Ruby
20
22
 
21
- $ gem install app_rail-airtable
23
+ **API keys have account scope in Airtable so it is recommended to create a new account for each project so that API keys do not leak data, e.g. bob+<project name>@gmail.com. You can share the project with your main account so you don't need to login to separate accounts for each project.**
22
24
 
23
- ## Usage
25
+ You should create a model class for each table you want to use in your App. Model classes should extend `AppRail::Airtable::ApplicationRecord` and define [table name](https://github.com/sirupsen/airrecord#table) and [associations](https://github.com/sirupsen/airrecord#associations)
26
+
27
+ To provide support for routes, models can implement
28
+ * ar_list_item (index)
29
+ * ar_stack (show)
30
+ * self.create_as_json (create)
31
+ * self.update_as_json (update)
32
+
33
+ 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.
34
+
35
+ ### Servers
36
+ You should create a single server which extends `AppRail::Airtable::Sinatra`.
37
+
38
+ App Rail Airtable provides two helpers to generate routes
39
+
40
+ **resources(name, only:)**
41
+ Creates routes that map to a table. It delegates from the route to a model method
42
+ * `index` to `ar_list_item`
43
+ * `show` to `ar_stack`
44
+ * `create` to `self.create_as_json`
45
+ * `update` to `self.update_as_json`
24
46
 
25
- TODO: Write usage instructions here
47
+ **authenticable_resources(name, , only:)**
48
+ 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).
26
49
 
27
- ## Development
50
+ ### Generator
28
51
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
52
+ ```bash
53
+ bin/ara_generator <output_directory> <airtable_api_key> <airtable_base_id> [<json_schema>]
54
+ ```
30
55
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
56
+ #### Example
32
57
 
33
- ## Contributing
58
+ ```bash
59
+ bin/ara_generator ./test key1234567890 appwertyuiop '{"tables": [{"name": "DailyLogs", "fields": [{"name": "Date", "type": "date"}, {"name": "Score", "type": "integer"}], "associations": [{"name": "User", "type": "belongs_to", "model": "User"}], "ar_class_methods": [{"name": "ar_list_item", "properties": [{"type": "text", "value": "date"}, {"type": "detail_text", "value": "score"}]}], "ar_instance_methods": [{"name": "ar_stack_item", "properties": [{"type": "text", "label": "Date", "value": "date"}, {"type": "button", "label": "Score", "value": "score", "modalWorkflow": "", "style": "primary", "onSuccess": "forward", "sfSymbolName": ""}]}]}, {"name": "Users", "fields": [{"name": "Email", "type": "string"}, {"name": "Password Hash", "type": "string"}, {"name": "Access Token", "type": "string"}], "associations": [{"name": "DailyLogs", "type": "has_many", "model": "DailyLog"}], "authenticatable": "True"}]}'
60
+ ```
34
61
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/app_rail-airtable.
62
+ You can find more examples of schemas in [/examples/schemas](/examples/schemas)
36
63
 
64
+ ## Debugging
37
65
 
66
+ ### Listing Existing Routes
67
+ To get a complete list of the available routes in your Sinatra application, run the following code snippet:
68
+ ```ruby
69
+ Server.routes.map do |method, routes|
70
+ routes.map { |r| r.first.to_s }.map do |route|
71
+ "#{method.rjust(7, ' ')} #{route}"
72
+ end
73
+ end.flatten.sort.each do |route|
74
+ puts route
75
+ end
76
+ ```
77
+ Output:
78
+ ```
79
+ GET /mock_items
80
+ GET /mock_items/:id
81
+ PUT /mock_items/:id
82
+ HEAD /mock_items
83
+ HEAD /mock_items/:id
84
+ POST /mock_items
85
+ ```
38
86
  ## License
39
87
 
40
88
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- task :default => :spec
8
+ task default: :spec
@@ -1,29 +1,40 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'lib/app_rail/airtable/version'
2
4
 
3
5
  Gem::Specification.new do |spec|
4
- spec.name = "app_rail-airtable"
6
+ spec.name = 'app_rail-airtable'
5
7
  spec.version = AppRail::Airtable::VERSION
6
- spec.authors = ["Matt Brooke-Smith"]
7
- spec.email = ["matt@futureworkshops.com"]
8
+ spec.authors = ['Matt Brooke-Smith']
9
+ spec.email = ['matt@futureworkshops.com']
8
10
 
9
- spec.summary = %q{Gem to help building App Rail servers using Airtable as a backend}
10
- spec.homepage = "https://github.com/FutureWorkshops/app_rail-airtable"
11
- spec.license = "MIT"
12
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
11
+ spec.summary = 'Gem to help building App Rail servers using Airtable as a backend'
12
+ spec.homepage = 'https://github.com/FutureWorkshops/app_rail-airtable'
13
+ spec.license = 'MIT'
14
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
13
15
 
14
- spec.metadata["homepage_uri"] = spec.homepage
15
- spec.metadata["source_code_uri"] = "https://github.com/FutureWorkshops/app_rail-airtable"
16
+ spec.metadata['homepage_uri'] = spec.homepage
17
+ spec.metadata['source_code_uri'] = 'https://github.com/FutureWorkshops/app_rail-airtable'
16
18
 
17
19
  # Specify which files should be added to the gem when it is released.
18
20
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
20
22
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
23
  end
22
- spec.require_paths = ["lib"]
24
+
25
+ spec.bindir = 'bin'
26
+ spec.executables << 'ara_generator'
27
+
28
+ spec.require_paths = ['lib']
23
29
  spec.add_dependency 'activesupport'
24
- spec.add_dependency 'sinatra'
25
30
  spec.add_dependency 'airrecord'
26
-
27
- spec.add_development_dependency 'rspec'
31
+ spec.add_dependency 'app_rail-steps'
32
+ spec.add_dependency 'bcrypt'
33
+ spec.add_dependency 'faraday', '~> 2.2'
34
+ spec.add_dependency 'faraday-net_http_persistent', '~> 2.0' # workaround to make Faraday work after upgrading to 2.2.0
35
+ spec.add_dependency 'sinatra'
36
+ spec.add_dependency 'thor'
37
+
28
38
  spec.add_development_dependency 'rack-test'
29
- end
39
+ spec.add_development_dependency 'rspec'
40
+ end
data/bin/ara_generator ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'app_rail/airtable/generator'
6
+ require 'byebug'
7
+
8
+ AppRail::Airtable::Generator.start(ARGV)
data/bin/console CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require "bundler/setup"
4
- require "app_rail/airtable"
4
+ require 'bundler/setup'
5
+ require 'app_rail/airtable'
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
7
8
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +11,5 @@ require "app_rail/airtable"
10
11
  # require "pry"
11
12
  # Pry.start
12
13
 
13
- require "irb"
14
+ require 'irb'
14
15
  IRB.start(__FILE__)
@@ -0,0 +1,86 @@
1
+ {
2
+ "tables": [
3
+ {
4
+ "name": "DailyLogs",
5
+ "fields": [
6
+ {
7
+ "name": "Date",
8
+ "type": "date"
9
+ },
10
+ {
11
+ "name": "Score",
12
+ "type": "integer"
13
+ }
14
+ ],
15
+ "associations": [
16
+ {
17
+ "name": "User",
18
+ "type": "belongs_to",
19
+ "model": "User"
20
+ }
21
+ ],
22
+ "ar_class_methods": [
23
+ {
24
+ "name": "ar_list_item",
25
+ "properties": [
26
+ {
27
+ "type": "text",
28
+ "value": "date"
29
+ },
30
+ {
31
+ "type": "detail_text",
32
+ "value": "score"
33
+ }
34
+ ]
35
+ }
36
+ ],
37
+ "ar_instance_methods": [
38
+ {
39
+ "name": "ar_stack_item",
40
+ "properties": [
41
+ {
42
+ "type": "text",
43
+ "label": "Date",
44
+ "value": "date"
45
+ },
46
+ {
47
+ "type": "button",
48
+ "label": "Score",
49
+ "value": "score",
50
+ "modalWorkflow": "",
51
+ "style": "primary",
52
+ "onSuccess": "forward",
53
+ "sfSymbolName": ""
54
+ }
55
+ ]
56
+ }
57
+ ],
58
+ "authenticatable": "True"
59
+ },
60
+ {
61
+ "name": "Users",
62
+ "fields": [
63
+ {
64
+ "name": "Email",
65
+ "type": "string"
66
+ },
67
+ {
68
+ "name": "Password Hash",
69
+ "type": "string"
70
+ },
71
+ {
72
+ "name": "Access Token",
73
+ "type": "string"
74
+ }
75
+ ],
76
+ "associations": [
77
+ {
78
+ "name": "DailyLogs",
79
+ "type": "has_many",
80
+ "model": "DailyLog"
81
+ }
82
+ ],
83
+ "authenticatable": "True"
84
+ }
85
+ ]
86
+ }
@@ -0,0 +1,85 @@
1
+ {
2
+ "tables": [
3
+ {
4
+ "name": "DailyLogs",
5
+ "fields": [
6
+ {
7
+ "name": "Date",
8
+ "type": "date"
9
+ },
10
+ {
11
+ "name": "Score",
12
+ "type": "integer"
13
+ }
14
+ ],
15
+ "associations": [
16
+ {
17
+ "name": "User",
18
+ "type": "belongs_to",
19
+ "model": "User"
20
+ }
21
+ ],
22
+ "ar_class_methods": [
23
+ {
24
+ "name": "ar_list_item",
25
+ "properties": [
26
+ {
27
+ "type": "text",
28
+ "value": "date"
29
+ },
30
+ {
31
+ "type": "detail_text",
32
+ "value": "score"
33
+ }
34
+ ]
35
+ }
36
+ ],
37
+ "ar_instance_methods": [
38
+ {
39
+ "name": "ar_stack_item",
40
+ "properties": [
41
+ {
42
+ "type": "text",
43
+ "label": "Date",
44
+ "value": "date"
45
+ },
46
+ {
47
+ "type": "button",
48
+ "label": "Score",
49
+ "value": "score",
50
+ "modalWorkflow": "",
51
+ "style": "primary",
52
+ "onSuccess": "forward",
53
+ "sfSymbolName": ""
54
+ }
55
+ ]
56
+ }
57
+ ]
58
+ },
59
+ {
60
+ "name": "Users",
61
+ "fields": [
62
+ {
63
+ "name": "Email",
64
+ "type": "string"
65
+ },
66
+ {
67
+ "name": "Password Hash",
68
+ "type": "string"
69
+ },
70
+ {
71
+ "name": "Access Token",
72
+ "type": "string"
73
+ }
74
+ ],
75
+ "associations": [
76
+ {
77
+ "name": "DailyLogs",
78
+ "type": "has_many",
79
+ "model": "DailyLog"
80
+ }
81
+ ],
82
+ "authenticatable": "True"
83
+ }
84
+ ]
85
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "tables": [
3
+ {
4
+ "name": "Users",
5
+ "fields": [
6
+ {
7
+ "name": "Forename",
8
+ "type": "string"
9
+ },
10
+ {
11
+ "name": "Surname",
12
+ "type": "string"
13
+ },
14
+ {
15
+ "name": "NHS Number",
16
+ "type": "integer"
17
+ },
18
+ {
19
+ "name": "Date of Birth",
20
+ "type": "date"
21
+ },
22
+ {
23
+ "name": "Vaccine",
24
+ "type": "string"
25
+ }
26
+ ],
27
+ "associations": [
28
+ {
29
+ "name": "Vaccination Appointments",
30
+ "type": "has_many",
31
+ "model": "VaccinationAppointment"
32
+ }
33
+ ],
34
+ "ar_class_methods": [
35
+ {
36
+ "name": "ar_list_item",
37
+ "properties": [
38
+ {
39
+ "type": "text",
40
+ "value": "forename"
41
+ },
42
+ {
43
+ "type": "detail_text",
44
+ "value": "surname"
45
+ }
46
+ ]
47
+ }
48
+ ]
49
+ }
50
+ ]
51
+ }