bullet_train-api 1.2.9 → 1.2.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/api/open_api_controller.rb +45 -14
- data/app/controllers/concerns/api/controllers/base.rb +23 -5
- data/app/controllers/concerns/api/v1/users/controller_base.rb +24 -6
- data/app/views/account/platform/access_tokens/_index.html.erb +1 -8
- data/app/views/account/platform/connections/new.html.erb +6 -6
- data/lib/bullet_train/api/version.rb +1 -1
- data/lib/bullet_train/api.rb +10 -0
- data/lib/tasks/bullet_train/api_tasks.rake +17 -1
- data/lib/tokens_controller.rb +21 -0
- metadata +4 -6
- data/app/views/account/platform/applications/_application.json.jbuilder +0 -9
- data/app/views/account/platform/applications/index.json.jbuilder +0 -1
- data/app/views/account/platform/applications/show.json.jbuilder +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4f8d6d77dec24dd8d2766815d042af01738dca790794a8b25566e7cd856460d
|
4
|
+
data.tar.gz: 9824629fabe7e7c6cbc6ad32aa33c1f15a2d6c96f41549c0222565cdfba4c708
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a2d7f5e1718ab4fc68507c0c63a0ebe19cb3f7ef1c235e05ba96b41c93902f309300778431b4c0b6e66b4b24b9bdbced1761507471ac488ad4dbcd4c9208b82
|
7
|
+
data.tar.gz: b1e2fe3aac4d7e8bfe715b02c1741681fbac2d93a8cb6255bc69b5f8529d5a2ec694690ad2908a83a6788985b3be412de560a1dc0ccc50a1b30ef0dad9b16be8
|
@@ -25,6 +25,10 @@ module OpenApiHelper
|
|
25
25
|
result
|
26
26
|
end
|
27
27
|
|
28
|
+
def gem_paths
|
29
|
+
@gem_paths ||= `bundle show --paths`.lines.map { |gem_path| gem_path.chomp }
|
30
|
+
end
|
31
|
+
|
28
32
|
def automatic_paths_for(model, parent, except: [])
|
29
33
|
output = render("api/#{@version}/open_api/shared/paths", except: except)
|
30
34
|
output = Scaffolding::Transformer.new(model.name, [parent&.name]).transform_string(output).html_safe
|
@@ -33,7 +37,7 @@ module OpenApiHelper
|
|
33
37
|
|
34
38
|
def automatic_components_for(model, locals: {})
|
35
39
|
path = "app/views/api/#{@version}"
|
36
|
-
paths = ([path] +
|
40
|
+
paths = ([path] + gem_paths.map { |gem_path| "#{gem_path}/#{path}" })
|
37
41
|
jbuilder = Jbuilder::Schema.renderer(paths, locals: {
|
38
42
|
# If we ever get to the point where we need a real model here, we should implement an example team in seeds that we can source it from.
|
39
43
|
model.name.underscore.split("/").last.to_sym => model.new,
|
@@ -50,20 +54,41 @@ module OpenApiHelper
|
|
50
54
|
|
51
55
|
attributes_output = JSON.parse(schema_json)
|
52
56
|
|
53
|
-
|
54
|
-
|
55
|
-
if
|
56
|
-
|
57
|
-
|
57
|
+
# Rails attachments aren't technically attributes in a model,
|
58
|
+
# so we add the attributes manually to make them available in the API.
|
59
|
+
if model.attachment_reflections.any?
|
60
|
+
model.attachment_reflections.each do |reflection|
|
61
|
+
attribute_name = reflection.first
|
58
62
|
|
59
|
-
|
60
|
-
|
61
|
-
|
63
|
+
attributes_output["properties"][attribute_name] = {
|
64
|
+
"type" => "object",
|
65
|
+
"description" => attribute_name.titleize.to_s
|
66
|
+
}
|
67
|
+
|
68
|
+
attributes_output["example"].merge!({attribute_name.to_s => nil})
|
69
|
+
end
|
70
|
+
end
|
62
71
|
|
63
|
-
(
|
64
|
-
|
65
|
-
|
66
|
-
|
72
|
+
if has_strong_parameters?("Api::#{@version.upcase}::#{model.name.pluralize}Controller".constantize)
|
73
|
+
strong_params_module = "Api::#{@version.upcase}::#{model.name.pluralize}Controller::StrongParameters".constantize
|
74
|
+
strong_parameter_keys = BulletTrain::Api::StrongParametersReporter.new(model, strong_params_module).report
|
75
|
+
if strong_parameter_keys.last.is_a?(Hash)
|
76
|
+
strong_parameter_keys += strong_parameter_keys.pop.keys
|
77
|
+
end
|
78
|
+
|
79
|
+
parameters_output = JSON.parse(schema_json)
|
80
|
+
parameters_output["required"].select! { |key| strong_parameter_keys.include?(key.to_sym) }
|
81
|
+
parameters_output["properties"].select! { |key, value| strong_parameter_keys.include?(key.to_sym) }
|
82
|
+
|
83
|
+
(
|
84
|
+
indent(attributes_output.to_yaml.gsub("---", "#{model.name.gsub("::", "")}Attributes:"), 3) +
|
85
|
+
indent(" " + parameters_output.to_yaml.gsub("---", "#{model.name.gsub("::", "")}Parameters:"), 3)
|
86
|
+
).html_safe
|
87
|
+
else
|
88
|
+
|
89
|
+
indent(attributes_output.to_yaml.gsub("---", "#{model.name.gsub("::", "")}Attributes:"), 3)
|
90
|
+
.html_safe
|
91
|
+
end
|
67
92
|
end
|
68
93
|
|
69
94
|
def paths_for(model)
|
@@ -76,7 +101,6 @@ module OpenApiHelper
|
|
76
101
|
heading = t("#{current_model.name.underscore.pluralize}.fields.#{attribute}.heading")
|
77
102
|
attribute_data = current_model.columns_hash[attribute.to_s]
|
78
103
|
|
79
|
-
# TODO: File fields don't show up in the columns_hash. How should we handle these?
|
80
104
|
# Default to `string` when the type returns nil.
|
81
105
|
type = attribute_data.nil? ? "string" : attribute_data.type
|
82
106
|
|
@@ -88,6 +112,13 @@ module OpenApiHelper
|
|
88
112
|
indent(attribute_block.chomp, 2)
|
89
113
|
end
|
90
114
|
alias_method :parameter, :attribute
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def has_strong_parameters?(controller)
|
119
|
+
methods = controller.action_methods
|
120
|
+
methods.include?("create") || methods.include?("update")
|
121
|
+
end
|
91
122
|
end
|
92
123
|
|
93
124
|
class Api::OpenApiController < ApplicationController
|
@@ -4,6 +4,10 @@ require "pagy_cursor/pagy/extras/uuid_cursor"
|
|
4
4
|
module Api::Controllers::Base
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
+
# We need this to show custom error that user is not authenticated
|
8
|
+
# neither with Doorkeeper nor with Devise
|
9
|
+
class NotAuthenticatedError < StandardError; end
|
10
|
+
|
7
11
|
included do
|
8
12
|
include ActionController::Helpers
|
9
13
|
helper ApplicationHelper
|
@@ -42,6 +46,10 @@ module Api::Controllers::Base
|
|
42
46
|
render json: {error: "Not found"}, status: :not_found
|
43
47
|
end
|
44
48
|
|
49
|
+
rescue_from NotAuthenticatedError do |exception|
|
50
|
+
render json: {error: "Invalid token or no user signed in"}, status: :unauthorized
|
51
|
+
end
|
52
|
+
|
45
53
|
before_action :apply_pagination, only: [:index]
|
46
54
|
end
|
47
55
|
|
@@ -57,14 +65,24 @@ module Api::Controllers::Base
|
|
57
65
|
end
|
58
66
|
|
59
67
|
def current_user
|
60
|
-
|
68
|
+
@current_user ||= if doorkeeper_token
|
69
|
+
User.find_by(id: doorkeeper_token[:resource_owner_id])
|
70
|
+
else
|
71
|
+
warden.authenticate(scope: :user)
|
72
|
+
end
|
73
|
+
|
61
74
|
# TODO Remove this rescue once workspace clusters can write to this column on the identity server.
|
62
75
|
# TODO Make this logic configurable so that downstream developers can write different methods for this column getting updated.
|
63
|
-
|
64
|
-
|
65
|
-
|
76
|
+
if doorkeeper_token
|
77
|
+
begin
|
78
|
+
doorkeeper_token.update(last_used_at: Time.zone.now)
|
79
|
+
rescue ActiveRecord::StatementInvalid => _
|
80
|
+
end
|
66
81
|
end
|
67
|
-
|
82
|
+
|
83
|
+
raise NotAuthenticatedError unless @current_user
|
84
|
+
|
85
|
+
@current_user
|
68
86
|
end
|
69
87
|
|
70
88
|
def current_team
|
@@ -4,16 +4,28 @@ module Api::V1::Users::ControllerBase
|
|
4
4
|
module StrongParameters
|
5
5
|
# Only allow a list of trusted parameters through.
|
6
6
|
def user_params
|
7
|
-
|
8
|
-
|
7
|
+
password_fields = [
|
8
|
+
:password,
|
9
|
+
:current_password,
|
10
|
+
:password_confirmation
|
11
|
+
]
|
12
|
+
general_fields = [
|
9
13
|
:email,
|
10
14
|
:first_name,
|
11
15
|
:last_name,
|
12
16
|
:time_zone,
|
13
|
-
:locale
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
+
:locale
|
18
|
+
]
|
19
|
+
|
20
|
+
selected_fields = if params.is_a?(BulletTrain::Api::StrongParametersReporter)
|
21
|
+
password_fields + general_fields
|
22
|
+
else
|
23
|
+
(params["commit"] == t(".buttons.update_password")) ? password_fields : general_fields
|
24
|
+
end
|
25
|
+
|
26
|
+
strong_params = params.require(:user).permit(
|
27
|
+
*permitted_fields,
|
28
|
+
*selected_fields,
|
17
29
|
# 🚅 super scaffolding will insert new fields above this line.
|
18
30
|
*permitted_arrays,
|
19
31
|
# 🚅 super scaffolding will insert new arrays above this line.
|
@@ -50,4 +62,10 @@ module Api::V1::Users::ControllerBase
|
|
50
62
|
# GET /api/v1/users/:id
|
51
63
|
def show
|
52
64
|
end
|
65
|
+
|
66
|
+
# PUT /api/v1/users/:id
|
67
|
+
# TODO: Implement this!
|
68
|
+
def update
|
69
|
+
raise "Not implemented"
|
70
|
+
end
|
53
71
|
end
|
@@ -36,14 +36,7 @@
|
|
36
36
|
<%= render "shared/tables/checkbox", object: access_token %>
|
37
37
|
<td><%= render 'shared/attributes/code', attribute: :token, secret: true %></td>
|
38
38
|
<td><%= render 'shared/attributes/text', attribute: :description %></td>
|
39
|
-
<td>
|
40
|
-
<% if access_token.last_used_at %>
|
41
|
-
<%= render 'shared/attributes/date_and_time', attribute: :last_used_at %>
|
42
|
-
<% else %>
|
43
|
-
<% # TODO Make it so we can just define a `default` key for `last_used_at` in the locale file and it will us that when present. %>
|
44
|
-
Never
|
45
|
-
<% end %>
|
46
|
-
</td>
|
39
|
+
<td><%= render 'shared/attributes/date_and_time', attribute: :last_used_at %></td>
|
47
40
|
<%# 🚅 super scaffolding will insert new fields above this line. %>
|
48
41
|
<td><%= render 'shared/attributes/date_and_time', attribute: :created_at %></td>
|
49
42
|
<td class="buttons">
|
@@ -3,22 +3,22 @@
|
|
3
3
|
<% p.content_for :body do %>
|
4
4
|
<ul class="space-y" data-turbo="false">
|
5
5
|
<% @teams.each do |team| %>
|
6
|
-
<li class="bg-white border overflow-hidden sm:rounded-md dark:bg-
|
6
|
+
<li class="bg-white border overflow-hidden sm:rounded-md dark:bg-slate-400">
|
7
7
|
<% body = capture do %>
|
8
8
|
<div class="px-4 py-4 flex items-center sm:pl-8 sm:pr-6">
|
9
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-
|
10
|
+
<div class="flex text-xl font-semibold text-blue uppercase group-hover:text-blue-800 tracking-widest dark:text-white">
|
11
11
|
<%= team.name %>
|
12
12
|
</div>
|
13
13
|
<% unless can? :connect, team %>
|
14
|
-
<div class="ml-5 flex-shrink-0 text-
|
14
|
+
<div class="ml-5 flex-shrink-0 text-slate-400">
|
15
15
|
<%= t(".not_allowed") %>
|
16
16
|
</div>
|
17
17
|
<% end %>
|
18
18
|
</div>
|
19
19
|
<% if can? :connect, team %>
|
20
20
|
<div class="ml-5 flex-shrink-0">
|
21
|
-
<svg class="h-5 w-5 text-
|
21
|
+
<svg class="h-5 w-5 text-slate-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
22
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
23
|
</svg>
|
24
24
|
</div>
|
@@ -27,11 +27,11 @@
|
|
27
27
|
<% end %>
|
28
28
|
|
29
29
|
<% if can? :connect, team %>
|
30
|
-
<%= link_to request.url + "&team_id=#{team.id}", class: "group block hover:bg-
|
30
|
+
<%= link_to request.url + "&team_id=#{team.id}", class: "group block hover:bg-slate-50 dark:hover:bg-slate-400 dark:text-slate-800", data: {controller: "connection-workflow", action: "connection-workflow#disableTeamButton"} do %>
|
31
31
|
<%= body %>
|
32
32
|
<% end %>
|
33
33
|
<% else %>
|
34
|
-
<div class="block dark:text-
|
34
|
+
<div class="block dark:text-slate-800">
|
35
35
|
<%= body %>
|
36
36
|
</div>
|
37
37
|
<% end %>
|
data/lib/bullet_train/api.rb
CHANGED
@@ -30,5 +30,15 @@ module BulletTrain
|
|
30
30
|
def self.all_versions
|
31
31
|
(initial_version_numeric..current_version_numeric).map { |version| "v#{version}".to_sym }
|
32
32
|
end
|
33
|
+
|
34
|
+
def self.set_configuration(application_class)
|
35
|
+
application_class.config.to_prepare do
|
36
|
+
Doorkeeper::ApplicationController.layout "devise"
|
37
|
+
|
38
|
+
if Doorkeeper::TokensController
|
39
|
+
require_relative "../tokens_controller"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
33
43
|
end
|
34
44
|
end
|
@@ -8,7 +8,8 @@ namespace :bullet_train do
|
|
8
8
|
# Calculate new version.
|
9
9
|
initializer_content = File.new("config/initializers/api.rb").readline
|
10
10
|
previous_version = initializer_content.scan(/v\d+/).pop
|
11
|
-
|
11
|
+
new_version_int = previous_version.scan(/\d+/).pop.to_i + 1
|
12
|
+
new_version = "v#{new_version_int}"
|
12
13
|
|
13
14
|
# Update initializer.
|
14
15
|
File.write("config/initializers/api.rb", initializer_content.gsub(previous_version, new_version))
|
@@ -70,6 +71,21 @@ namespace :bullet_train do
|
|
70
71
|
end
|
71
72
|
Scaffolding::FileManipulator.write("config/routes.rb", updated_file_contents)
|
72
73
|
|
74
|
+
# Update application locale for each locale that exists.
|
75
|
+
I18n.available_locales.each do |lang|
|
76
|
+
file = "config/locales/#{lang}/application.#{lang}.yml"
|
77
|
+
transformer = Scaffolding::Transformer.new("", "")
|
78
|
+
|
79
|
+
if File.exist?(file)
|
80
|
+
transformer.add_line_to_file(
|
81
|
+
file,
|
82
|
+
"#{new_version_int}: #{new_version.upcase}",
|
83
|
+
Scaffolding::Transformer::RUBY_NEW_API_VERSION_HOOK,
|
84
|
+
prepend: true
|
85
|
+
)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
73
89
|
puts "Finished bumping to #{new_version}"
|
74
90
|
end
|
75
91
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# TODO Is there a better way to implement this?
|
2
|
+
# This monkey patch is required to ensure the OAuth2 token includes which team was connected to.
|
3
|
+
# It gets required by BulletTrain::Api.set_configuration.
|
4
|
+
|
5
|
+
class Doorkeeper::TokensController
|
6
|
+
def create
|
7
|
+
headers.merge!(authorize_response.headers)
|
8
|
+
|
9
|
+
user = if authorize_response.is_a?(Doorkeeper::OAuth::ErrorResponse)
|
10
|
+
nil
|
11
|
+
else
|
12
|
+
User.find(authorize_response.token.resource_owner_id)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Add the selected `team_id` to this response.
|
16
|
+
render json: authorize_response.body.merge(user&.teams&.one? ? {"team_id" => user.team_ids.first} : {}),
|
17
|
+
status: authorize_response.status
|
18
|
+
rescue Doorkeeper::Errors::DoorkeeperError => e
|
19
|
+
handle_token_exception(e)
|
20
|
+
end
|
21
|
+
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.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Culver
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-02-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: standard
|
@@ -151,17 +151,14 @@ files:
|
|
151
151
|
- app/views/account/platform/access_tokens/index.html.erb
|
152
152
|
- app/views/account/platform/access_tokens/new.html.erb
|
153
153
|
- app/views/account/platform/access_tokens/show.html.erb
|
154
|
-
- app/views/account/platform/applications/_application.json.jbuilder
|
155
154
|
- app/views/account/platform/applications/_breadcrumbs.html.erb
|
156
155
|
- app/views/account/platform/applications/_form.html.erb
|
157
156
|
- app/views/account/platform/applications/_index.html.erb
|
158
157
|
- app/views/account/platform/applications/_menu_item.html.erb
|
159
158
|
- app/views/account/platform/applications/edit.html.erb
|
160
159
|
- app/views/account/platform/applications/index.html.erb
|
161
|
-
- app/views/account/platform/applications/index.json.jbuilder
|
162
160
|
- app/views/account/platform/applications/new.html.erb
|
163
161
|
- app/views/account/platform/applications/show.html.erb
|
164
|
-
- app/views/account/platform/applications/show.json.jbuilder
|
165
162
|
- app/views/account/platform/connections/new.html.erb
|
166
163
|
- app/views/api/v1/open_api/shared/_paths.yaml.erb
|
167
164
|
- app/views/api/v1/open_api/teams/_paths.yaml.erb
|
@@ -196,6 +193,7 @@ files:
|
|
196
193
|
- lib/bullet_train/platform.rb
|
197
194
|
- lib/bullet_train/platform/connection_workflow.rb
|
198
195
|
- lib/tasks/bullet_train/api_tasks.rake
|
196
|
+
- lib/tokens_controller.rb
|
199
197
|
homepage: https://github.com/bullet-train-co/bullet_train-api
|
200
198
|
licenses:
|
201
199
|
- MIT
|
@@ -217,7 +215,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
217
215
|
- !ruby/object:Gem::Version
|
218
216
|
version: '0'
|
219
217
|
requirements: []
|
220
|
-
rubygems_version: 3.
|
218
|
+
rubygems_version: 3.4.1
|
221
219
|
signing_key:
|
222
220
|
specification_version: 4
|
223
221
|
summary: Bullet Train API
|
@@ -1 +0,0 @@
|
|
1
|
-
json.array! @applications, partial: "platform/applications/application", as: :application
|
@@ -1 +0,0 @@
|
|
1
|
-
json.partial! "platform/applications/application", application: @application
|