bullet_train-api 1.2.4 → 1.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/concerns/api/v1/users/controller_base.rb +8 -0
- data/app/models/platform/access_token.rb +13 -0
- data/app/models/platform/application.rb +1 -1
- data/app/views/account/platform/applications/index.html.erb +1 -0
- data/app/views/account/platform/connections/new.html.erb +42 -0
- data/config/locales/en/platform/access_tokens.en.yml +3 -0
- data/config/locales/en/platform/connections.en.yml +7 -0
- data/docs/api.md +1 -1
- data/docs/zapier.md +46 -0
- data/lib/bullet_train/api/version.rb +1 -1
- data/lib/bullet_train/api.rb +1 -0
- data/lib/bullet_train/platform/connection_workflow.rb +64 -0
- data/lib/bullet_train/platform.rb +2 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eea6e15f732345ad8b79974221655546fb043fe728714cb36fd1be94de87ca65
|
4
|
+
data.tar.gz: 765e5cd3fb11a1383627ee7a78d3420fa474148c4c9cdbd38a2dcc1b8c9d269c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2fffd4bb4375861f09ede137834e8ac90e38b252f2dac98f75db098dbb5a6ae73d24a5cd4f6b36e70bccf994c60f348681bb25a41d775a0767e60cb45bc9106
|
7
|
+
data.tar.gz: 833751b5331a288a1b63b12c47bdd447b800b0eea1c29341ad59e9507c91682f1c8f309de584a5d6c42cb1df81cdd757f1c5b2f8da98ec43c5d525a2f78537d4
|
@@ -30,6 +30,8 @@ module Api::V1::Users::ControllerBase
|
|
30
30
|
member_actions: (defined?(MEMBER_ACTIONS) ? MEMBER_ACTIONS : []),
|
31
31
|
collection_actions: (defined?(COLLECTION_ACTIONS) ? COLLECTION_ACTIONS : [])
|
32
32
|
|
33
|
+
prepend_before_action :resolve_me
|
34
|
+
|
33
35
|
private
|
34
36
|
|
35
37
|
include StrongParameters
|
@@ -39,6 +41,12 @@ module Api::V1::Users::ControllerBase
|
|
39
41
|
def index
|
40
42
|
end
|
41
43
|
|
44
|
+
def resolve_me
|
45
|
+
if current_user && params[:id]&.downcase == "me"
|
46
|
+
params[:id] = current_user.id
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
42
50
|
# GET /api/v1/users/:id
|
43
51
|
def show
|
44
52
|
end
|
@@ -28,5 +28,18 @@ class Platform::AccessToken < ApplicationRecord
|
|
28
28
|
def label_string
|
29
29
|
description
|
30
30
|
end
|
31
|
+
|
32
|
+
def system_level?
|
33
|
+
return false unless application
|
34
|
+
!application.team_id
|
35
|
+
end
|
36
|
+
|
37
|
+
def description
|
38
|
+
if system_level?
|
39
|
+
application.name
|
40
|
+
else
|
41
|
+
super
|
42
|
+
end
|
43
|
+
end
|
31
44
|
# 🚅 add methods above.
|
32
45
|
end
|
@@ -4,7 +4,7 @@ class Platform::Application < ApplicationRecord
|
|
4
4
|
include Doorkeeper::Orm::ActiveRecord::Mixins::Application
|
5
5
|
# 🚅 add concerns above.
|
6
6
|
|
7
|
-
belongs_to :team
|
7
|
+
belongs_to :team, optional: true
|
8
8
|
# 🚅 add belongs_to associations above.
|
9
9
|
|
10
10
|
# 🚅 add has_many associations above.
|
@@ -2,5 +2,6 @@
|
|
2
2
|
<% p.content_for :title, t('.section') %>
|
3
3
|
<% p.content_for :body do %>
|
4
4
|
<%= render 'index', applications: @applications %>
|
5
|
+
<%= render 'account/platform/access_tokens/index', access_tokens: @team.platform_agent_access_tokens, context: @team %>
|
5
6
|
<% end %>
|
6
7
|
<% end %>
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<%= render 'account/shared/workflow/box' do |p| %>
|
2
|
+
<% p.content_for :title, t('.header', application_name: @application.name) %>
|
3
|
+
<% p.content_for :body do %>
|
4
|
+
<ul class="space-y" data-turbo="false">
|
5
|
+
<% @teams.each do |team| %>
|
6
|
+
<li class="bg-white border overflow-hidden sm:rounded-md dark:bg-sealBlue-400">
|
7
|
+
<% body = capture do %>
|
8
|
+
<div class="px-4 py-4 flex items-center sm:pl-8 sm:pr-6">
|
9
|
+
<div class="min-w-0 flex-1 sm:flex sm:items-center sm:justify-between">
|
10
|
+
<div class="flex text-xl font-semibold text-blue uppercase group-hover:text-blue-dark tracking-widest dark:text-white">
|
11
|
+
<%= team.name %>
|
12
|
+
</div>
|
13
|
+
<% unless can? :connect, team %>
|
14
|
+
<div class="ml-5 flex-shrink-0 text-gray-400">
|
15
|
+
<%= t(".not_allowed") %>
|
16
|
+
</div>
|
17
|
+
<% end %>
|
18
|
+
</div>
|
19
|
+
<% if can? :connect, team %>
|
20
|
+
<div class="ml-5 flex-shrink-0">
|
21
|
+
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
22
|
+
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
|
23
|
+
</svg>
|
24
|
+
</div>
|
25
|
+
<% end %>
|
26
|
+
</div>
|
27
|
+
<% end %>
|
28
|
+
|
29
|
+
<% if can? :connect, team %>
|
30
|
+
<%= link_to request.url + "&team_id=#{team.id}", class: "group block hover:bg-gray-50 dark:hover:bg-sealBlue-400 dark:text-sealBlue-800" do %>
|
31
|
+
<%= body %>
|
32
|
+
<% end %>
|
33
|
+
<% else %>
|
34
|
+
<div class="block dark:text-sealBlue-800">
|
35
|
+
<%= body %>
|
36
|
+
</div>
|
37
|
+
<% end %>
|
38
|
+
</li>
|
39
|
+
<% end %>
|
40
|
+
</ul>
|
41
|
+
<% end %>
|
42
|
+
<% end %>
|
@@ -67,6 +67,9 @@ en:
|
|
67
67
|
platform/application:
|
68
68
|
header: API Access Tokens
|
69
69
|
description: You can use Access Tokens to allow %{application_name} to make requests to the API.
|
70
|
+
team:
|
71
|
+
header: Platform Connections
|
72
|
+
description: The following Platform Applications are connected to your account. The Access Tokens issued to these Platform Applications are available below in case you need to debug these integrations.
|
70
73
|
fields: *fields
|
71
74
|
buttons: *buttons
|
72
75
|
show:
|
data/docs/api.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# REST API
|
2
|
-
We believe every SaaS application should have an API and [webhooks](
|
2
|
+
We believe every SaaS application should have an API and [webhooks](/docs/webhooks/outgoing.md) available to users, so Bullet Train aims to help automate the creation of a production-grade REST API using Rails-native tooling and provides a forward-thinking strategy for its long-term maintenance.
|
3
3
|
|
4
4
|
## Background
|
5
5
|
Vanilla Rails scaffolding actually provides simple API functionality out-of-the-box: You can append `.json` to the URL of any scaffold and it will render a JSON representation instead of an HTML view. This functionality continues to work in Bullet Train, but our API implementation also builds on this simple baseline using the same tools with additional organization and some new patterns.
|
data/docs/zapier.md
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# Integrating with Zapier
|
2
|
+
Bullet Train provides out-of-the-box support for Zapier. New Bullet Train projects include a preconfigured Zapier CLI project that is ready to `zapier deploy`.
|
3
|
+
|
4
|
+
## Background
|
5
|
+
Zapier was designed to take advantage of an application's existing [REST API](/docs/api.md), [outgoing webhook capabilities](/docs/webhooks/outgoing.md), and OAuth2 authorization workflows. Thankfully for us, Bullet Train provides the first two and pre-configures Doorkeeper to provide the latter. We also have an smooth OAuth2 connection workflow that accounts for the mismatch between the user-based OAuth2 standard and team-based multitenancy.
|
6
|
+
|
7
|
+
## Prerequitesites
|
8
|
+
- You must be developing in an environment with [tunneling enabled](/docs/tunneling.md).
|
9
|
+
|
10
|
+
## Getting Started in Development
|
11
|
+
First, install the Zapier CLI tooling and deploy:
|
12
|
+
|
13
|
+
```
|
14
|
+
cd zapier
|
15
|
+
yarn install
|
16
|
+
zapier login
|
17
|
+
zapier register
|
18
|
+
zapier push
|
19
|
+
```
|
20
|
+
|
21
|
+
Once the application is registered in your account, you can re-run seeds in your development environment and it will create a `Platform::Application` record for Zapier:
|
22
|
+
|
23
|
+
```
|
24
|
+
cd ..
|
25
|
+
rake db:seed
|
26
|
+
```
|
27
|
+
|
28
|
+
When you do this for the first time, it will output some credentials for you to go back and configure for the Zapier application, like so:
|
29
|
+
|
30
|
+
```
|
31
|
+
cd zapier
|
32
|
+
zapier env:set 1.0.0 \
|
33
|
+
BASE_URL=https://andrewculver.ngrok.io \
|
34
|
+
CLIENT_ID=... \
|
35
|
+
CLIENT_SECRET=...
|
36
|
+
cd ..
|
37
|
+
```
|
38
|
+
|
39
|
+
You're done and can now test creating Zaps that react to example objects being created or create example objects based on other triggers.
|
40
|
+
|
41
|
+
## Deploying in Production
|
42
|
+
We haven't figured out a good suggested process for breaking out development and production versions of the Zapier application yet, but we'll update this section when we have.
|
43
|
+
|
44
|
+
## Future Plans
|
45
|
+
- Extend Super Scaffolding to automatically add new resources to the Zapier CLI project. For now you have to extend the Zapier CLI definitions manually.
|
46
|
+
|
data/lib/bullet_train/api.rb
CHANGED
@@ -0,0 +1,64 @@
|
|
1
|
+
require "bullet_train/platform"
|
2
|
+
|
3
|
+
class BulletTrain::Platform::ConnectionWorkflow
|
4
|
+
def to_proc
|
5
|
+
proc do
|
6
|
+
# Load the platform application in question.
|
7
|
+
# TODO Do we need to check the client secret or does Doorkeeper do that for us?
|
8
|
+
@application = Platform::Application.find_by(uid: params[:client_id])
|
9
|
+
|
10
|
+
# If the user is current signed in.
|
11
|
+
if current_user
|
12
|
+
# If the client application is opting into a team-level connection instead of a user-level connection, they have
|
13
|
+
# to select a team.
|
14
|
+
if params[:new_installation]
|
15
|
+
# If they selected a team on the team selection page.
|
16
|
+
if params[:team_id]
|
17
|
+
# Load the selected team.
|
18
|
+
team = Team.find(params[:team_id])
|
19
|
+
|
20
|
+
# Throw an error if they aren't allowed to create connections on this team.
|
21
|
+
authorize! :connect, team
|
22
|
+
|
23
|
+
# Create a faux membership and user that represent this connection.
|
24
|
+
# We have to do this because all our permissions are based on users, so team-level connections need a user.
|
25
|
+
faux_password = SecureRandom.hex
|
26
|
+
faux_user = User.create(
|
27
|
+
email: "noreply+#{SecureRandom.hex}@bullettrain.co",
|
28
|
+
password: faux_password,
|
29
|
+
password_confirmation: faux_password,
|
30
|
+
platform_agent_of: @application,
|
31
|
+
first_name: @application.name
|
32
|
+
)
|
33
|
+
|
34
|
+
# TODO I think we can get rid of `platform_agent` because we have `platform_agent_of_id`.
|
35
|
+
faux_membership = team.memberships.create(
|
36
|
+
user: faux_user,
|
37
|
+
platform_agent: true,
|
38
|
+
platform_agent_of: @application,
|
39
|
+
added_by: team.memberships.find_by(user: current_user)
|
40
|
+
)
|
41
|
+
|
42
|
+
faux_membership.roles << Role.admin
|
43
|
+
|
44
|
+
# We're done! Return the user, it'll be associated with the access grant and subsequent access token.
|
45
|
+
faux_user
|
46
|
+
else
|
47
|
+
# Show them a list of all their teams.
|
48
|
+
# We'll disable the teams they can't create connections for in the view.
|
49
|
+
@teams = current_user.teams
|
50
|
+
|
51
|
+
render "account/platform/connections/new"
|
52
|
+
end
|
53
|
+
else
|
54
|
+
# If the client application isn't specifically opting into a team-level installation, just connect on behalf of the user.
|
55
|
+
current_user
|
56
|
+
end
|
57
|
+
else
|
58
|
+
# If they're not signed in, redirect them to the sign in page and set a return URL via params.
|
59
|
+
# This is a crazy workaround for the fact that Safari doesn't let us create a session at the same time we redirect.
|
60
|
+
redirect_to new_user_session_path(return_url: request.url)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bullet_train-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Culver
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-12-
|
11
|
+
date: 2022-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: standard
|
@@ -162,6 +162,7 @@ files:
|
|
162
162
|
- app/views/account/platform/applications/new.html.erb
|
163
163
|
- app/views/account/platform/applications/show.html.erb
|
164
164
|
- app/views/account/platform/applications/show.json.jbuilder
|
165
|
+
- app/views/account/platform/connections/new.html.erb
|
165
166
|
- app/views/api/v1/open_api/shared/_paths.yaml.erb
|
166
167
|
- app/views/api/v1/open_api/teams/_paths.yaml.erb
|
167
168
|
- app/views/api/v1/open_api/users/_paths.yaml.erb
|
@@ -186,13 +187,17 @@ files:
|
|
186
187
|
- config/locales/en/me.en.yml
|
187
188
|
- config/locales/en/platform/access_tokens.en.yml
|
188
189
|
- config/locales/en/platform/applications.en.yml
|
190
|
+
- config/locales/en/platform/connections.en.yml
|
189
191
|
- config/routes.rb
|
190
192
|
- docs/api.md
|
191
193
|
- docs/api/versioning.md
|
194
|
+
- docs/zapier.md
|
192
195
|
- lib/bullet_train/api.rb
|
193
196
|
- lib/bullet_train/api/engine.rb
|
194
197
|
- lib/bullet_train/api/strong_parameters_reporter.rb
|
195
198
|
- lib/bullet_train/api/version.rb
|
199
|
+
- lib/bullet_train/platform.rb
|
200
|
+
- lib/bullet_train/platform/connection_workflow.rb
|
196
201
|
- lib/tasks/bullet_train/api_tasks.rake
|
197
202
|
homepage: https://github.com/bullet-train-co/bullet_train-api
|
198
203
|
licenses:
|