bullet_train-api 1.1.15 → 1.2.1
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 +4 -4
- data/app/controllers/account/platform/applications_controller.rb +17 -0
- data/app/controllers/api/open_api_controller.rb +14 -8
- data/app/controllers/concerns/api/controllers/base.rb +10 -14
- data/app/controllers/concerns/api/v1/users/controller_base.rb +3 -0
- data/app/models/platform/application.rb +1 -1
- data/app/views/api/v1/open_api/shared/_paths.yaml.erb +35 -12
- data/app/views/api/v1/open_api/teams/_paths.yaml.erb +22 -9
- data/app/views/api/v1/open_api/users/_paths.yaml.erb +22 -9
- data/config/locales/en/platform/applications.en.yml +2 -0
- data/config/routes.rb +4 -0
- data/lib/bullet_train/api/version.rb +1 -1
- data/lib/tasks/bullet_train/api_tasks.rake +76 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e3cec04f6456085bc115f66416e2f5fcaf249c0685166e8a46a88b79b4bd1978
|
4
|
+
data.tar.gz: 0b14b88a2aa523a9ce4d75de6ce79c4f0e81a46d0394085ca16e6b477bf66037
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ae4e8eaf3d5c89797e736de09866fc071427244120ed45b9fdced3881f433e91660e3372dfda36bda508c5af59a2db8ddb4e55354a7fc7dc3344e3a65b0cd106
|
7
|
+
data.tar.gz: 6551bce70c06a57a8b82511db07cbebbebf87f8f385bfb3bd4910166a2d7d5d5c4cbfa7a3c334d9bef1bbaf975eddf75b5a64175a16cae446a85d1cf9460ddd0
|
@@ -21,6 +21,23 @@ class Account::Platform::ApplicationsController < Account::ApplicationController
|
|
21
21
|
def edit
|
22
22
|
end
|
23
23
|
|
24
|
+
def provision
|
25
|
+
if ENV["TESTING_PROVISION_KEY"].present? && params[:key] == ENV["TESTING_PROVISION_KEY"]
|
26
|
+
user = User.create(email: "test@#{SecureRandom.hex}.example.com", password: (password = SecureRandom.hex), password_confirmation: password)
|
27
|
+
provision_team = current_user.teams.create(name: "provision-team-#{SecureRandom.hex}", time_zone: user.time_zone)
|
28
|
+
test_application = Platform::Application.new(name: "test-application-#{SecureRandom.hex}", team: provision_team)
|
29
|
+
|
30
|
+
if test_application.save
|
31
|
+
access_token = test_application.create_access_token
|
32
|
+
render json: {message: I18n.t("platform/applications.notifications.test_application_created"), team_id: provision_team.id, access_token: access_token.token}
|
33
|
+
else
|
34
|
+
render json: {errors: test_application.errors, status: :unprocessable_entity}
|
35
|
+
end
|
36
|
+
else
|
37
|
+
render json: {message: I18n.t("platform/applications.notifications.test_application_failure")}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
24
41
|
# POST /account/teams/:team_id/platform/applications
|
25
42
|
# POST /account/teams/:team_id/platform/applications.json
|
26
43
|
def create
|
@@ -6,6 +6,7 @@ module OpenApiHelper
|
|
6
6
|
lines.unshift(first_line).join.html_safe
|
7
7
|
end
|
8
8
|
|
9
|
+
# TODO: Remove this method? It's not being used anywhere
|
9
10
|
def components_for(model)
|
10
11
|
for_model model do
|
11
12
|
indent(render("api/#{@version}/open_api/#{model.name.underscore.pluralize}/components"), 2)
|
@@ -73,15 +74,20 @@ module OpenApiHelper
|
|
73
74
|
|
74
75
|
def attribute(attribute)
|
75
76
|
heading = t("#{current_model.name.underscore.pluralize}.fields.#{attribute}.heading")
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
77
|
+
attribute_data = current_model.columns_hash[attribute.to_s]
|
78
|
+
|
79
|
+
# TODO: File fields don't show up in the columns_hash. How should we handle these?
|
80
|
+
# Default to `string` when the type returns nil.
|
81
|
+
type = attribute_data.nil? ? "string" : attribute_data.type
|
82
|
+
|
83
|
+
attribute_block = <<~YAML
|
84
|
+
#{attribute}:
|
85
|
+
description: "#{heading}"
|
86
|
+
type: #{type}
|
87
|
+
YAML
|
88
|
+
indent(attribute_block.chomp, 2)
|
84
89
|
end
|
90
|
+
alias_method :parameter, :attribute
|
85
91
|
end
|
86
92
|
|
87
93
|
class Api::OpenApiController < ApplicationController
|
@@ -4,10 +4,6 @@ require "pagy_cursor/pagy/extras/uuid_cursor"
|
|
4
4
|
module Api::Controllers::Base
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
-
# TODO Why doesn't `before_action :doorkeeper_authorize!` throw an exception?
|
8
|
-
class NotAuthenticatedError < StandardError
|
9
|
-
end
|
10
|
-
|
11
7
|
included do
|
12
8
|
include ActionController::Helpers
|
13
9
|
helper ApplicationHelper
|
@@ -16,14 +12,13 @@ module Api::Controllers::Base
|
|
16
12
|
include Pagy::Backend
|
17
13
|
|
18
14
|
before_action :set_default_response_format
|
19
|
-
before_action :doorkeeper_authorize!
|
20
15
|
after_action :set_pagination_headers
|
21
16
|
|
22
17
|
def modify_url_params(url, new_params)
|
23
18
|
uri = URI.parse(url)
|
24
19
|
query = Rack::Utils.parse_query(uri.query)
|
25
20
|
new_params.each do |key, value|
|
26
|
-
query[key] = value
|
21
|
+
query[key.to_s] = value
|
27
22
|
end
|
28
23
|
uri.query = Rack::Utils.build_query(query)
|
29
24
|
uri.to_s
|
@@ -35,8 +30,9 @@ module Api::Controllers::Base
|
|
35
30
|
if @pagy.has_more?
|
36
31
|
if (collection = instance_variable_get(collection_variable))
|
37
32
|
next_cursor = collection.last.id
|
38
|
-
|
39
|
-
|
33
|
+
link_header = response.headers["Link"]
|
34
|
+
link_value = "<#{modify_url_params(request.url, after: next_cursor)}>; rel=\"next\""
|
35
|
+
response.headers["Link"] = link_header ? "#{link_header}, #{link_value}" : link_value
|
40
36
|
response.headers["Pagination-Next"] = next_cursor
|
41
37
|
end
|
42
38
|
end
|
@@ -46,10 +42,6 @@ module Api::Controllers::Base
|
|
46
42
|
render json: {error: "Not found"}, status: :not_found
|
47
43
|
end
|
48
44
|
|
49
|
-
rescue_from NotAuthenticatedError do |exception|
|
50
|
-
render json: {error: "Invalid token"}, status: :unauthorized
|
51
|
-
end
|
52
|
-
|
53
45
|
before_action :apply_pagination, only: [:index]
|
54
46
|
end
|
55
47
|
|
@@ -65,7 +57,7 @@ module Api::Controllers::Base
|
|
65
57
|
end
|
66
58
|
|
67
59
|
def current_user
|
68
|
-
raise
|
60
|
+
raise Doorkeeper::Errors::InvalidToken unless doorkeeper_token.present?
|
69
61
|
# TODO Remove this rescue once workspace clusters can write to this column on the identity server.
|
70
62
|
# TODO Make this logic configurable so that downstream developers can write different methods for this column getting updated.
|
71
63
|
begin
|
@@ -95,8 +87,12 @@ module Api::Controllers::Base
|
|
95
87
|
end
|
96
88
|
|
97
89
|
class_methods do
|
90
|
+
def controller_namespace
|
91
|
+
name.split("::").first(2).join("::")
|
92
|
+
end
|
93
|
+
|
98
94
|
def regex_to_remove_controller_namespace
|
99
|
-
/^#{
|
95
|
+
/^#{controller_namespace + "::"}/
|
100
96
|
end
|
101
97
|
end
|
102
98
|
end
|
@@ -11,6 +11,9 @@ module Api::V1::Users::ControllerBase
|
|
11
11
|
:last_name,
|
12
12
|
:time_zone,
|
13
13
|
:locale,
|
14
|
+
:current_password,
|
15
|
+
:password,
|
16
|
+
:password_confirmation,
|
14
17
|
# 🚅 super scaffolding will insert new fields above this line.
|
15
18
|
*permitted_arrays,
|
16
19
|
# 🚅 super scaffolding will insert new arrays above this line.
|
@@ -34,7 +34,7 @@ class Platform::Application < ApplicationRecord
|
|
34
34
|
def create_user_and_membership
|
35
35
|
faux_password = SecureRandom.hex
|
36
36
|
create_user(email: "noreply+#{SecureRandom.hex}@bullettrain.co", password: faux_password, password_confirmation: faux_password, first_name: label_string)
|
37
|
-
create_membership(team: team, user: user)
|
37
|
+
create_membership(team: team, user: user, platform_agent: true)
|
38
38
|
membership.roles << Role.admin
|
39
39
|
end
|
40
40
|
|
@@ -13,22 +13,23 @@
|
|
13
13
|
required: true
|
14
14
|
schema:
|
15
15
|
type: string
|
16
|
+
- $ref: "#/components/parameters/after"
|
16
17
|
responses:
|
17
18
|
"404":
|
18
19
|
description: "Not Found"
|
19
20
|
"200":
|
20
21
|
description: "OK"
|
22
|
+
headers:
|
23
|
+
Pagination-Next:
|
24
|
+
$ref: "#/components/headers/PaginationNext"
|
25
|
+
Link:
|
26
|
+
$ref: "#/components/headers/Link"
|
21
27
|
content:
|
22
28
|
application/json:
|
23
29
|
schema:
|
24
|
-
type:
|
25
|
-
|
26
|
-
|
27
|
-
type: array
|
28
|
-
items:
|
29
|
-
$ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingAttributes"
|
30
|
-
has_more:
|
31
|
-
type: boolean
|
30
|
+
type: array
|
31
|
+
items:
|
32
|
+
$ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingAttributes"
|
32
33
|
<% end %>
|
33
34
|
<% unless except.include?(:create) %>
|
34
35
|
post:
|
@@ -42,6 +43,17 @@
|
|
42
43
|
required: true
|
43
44
|
schema:
|
44
45
|
type: string
|
46
|
+
requestBody:
|
47
|
+
description: "Information about a new Tangible Thing"
|
48
|
+
required: true
|
49
|
+
content:
|
50
|
+
application/json:
|
51
|
+
schema:
|
52
|
+
type: object
|
53
|
+
properties:
|
54
|
+
scaffolding_completely_concrete_tangible_thing:
|
55
|
+
type: object
|
56
|
+
$ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingParameters"
|
45
57
|
responses:
|
46
58
|
"404":
|
47
59
|
description: "Not Found"
|
@@ -50,7 +62,7 @@
|
|
50
62
|
content:
|
51
63
|
application/json:
|
52
64
|
schema:
|
53
|
-
$ref: "#/components/schemas/
|
65
|
+
$ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingAttributes"
|
54
66
|
<% end %>
|
55
67
|
<% end %>
|
56
68
|
<% unless except.include?(:show) && except.include?(:update) && except.include?(:destroy) %>
|
@@ -81,6 +93,17 @@
|
|
81
93
|
operationId: updateScaffoldingCompletelyConcreteTangibleThings
|
82
94
|
parameters:
|
83
95
|
- $ref: "#/components/parameters/id"
|
96
|
+
requestBody:
|
97
|
+
description: "Information about updated fields in Tangible Thing"
|
98
|
+
required: true
|
99
|
+
content:
|
100
|
+
application/json:
|
101
|
+
schema:
|
102
|
+
type: object
|
103
|
+
properties:
|
104
|
+
scaffolding_completely_concrete_tangible_thing:
|
105
|
+
type: object
|
106
|
+
$ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingParameters"
|
84
107
|
responses:
|
85
108
|
"404":
|
86
109
|
description: "Not Found"
|
@@ -89,7 +112,7 @@
|
|
89
112
|
content:
|
90
113
|
application/json:
|
91
114
|
schema:
|
92
|
-
$ref: "#/components/schemas/
|
115
|
+
$ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingAttributes"
|
93
116
|
<% end %>
|
94
117
|
<% unless except.include?(:destroy) %>
|
95
118
|
delete:
|
@@ -102,7 +125,7 @@
|
|
102
125
|
responses:
|
103
126
|
"404":
|
104
127
|
description: "Not Found"
|
105
|
-
"
|
106
|
-
description: "
|
128
|
+
"204":
|
129
|
+
description: "No Content"
|
107
130
|
<% end %>
|
108
131
|
<% end %>
|
@@ -4,22 +4,24 @@
|
|
4
4
|
- Teams
|
5
5
|
summary: "List Teams"
|
6
6
|
operationId: listTeams
|
7
|
+
parameters:
|
8
|
+
- $ref: "#/components/parameters/after"
|
7
9
|
responses:
|
8
10
|
"404":
|
9
11
|
description: "Not Found"
|
10
12
|
"200":
|
11
13
|
description: "OK"
|
14
|
+
headers:
|
15
|
+
Pagination-Next:
|
16
|
+
$ref: "#/components/headers/PaginationNext"
|
17
|
+
Link:
|
18
|
+
$ref: "#/components/headers/Link"
|
12
19
|
content:
|
13
20
|
application/json:
|
14
21
|
schema:
|
15
|
-
type:
|
16
|
-
|
17
|
-
|
18
|
-
type: array
|
19
|
-
items:
|
20
|
-
$ref: "#/components/schemas/TeamAttributes"
|
21
|
-
has_more:
|
22
|
-
type: boolean
|
22
|
+
type: array
|
23
|
+
items:
|
24
|
+
$ref: "#/components/schemas/TeamAttributes"
|
23
25
|
/teams/{id}:
|
24
26
|
get:
|
25
27
|
tags:
|
@@ -44,6 +46,17 @@
|
|
44
46
|
operationId: updateTeam
|
45
47
|
parameters:
|
46
48
|
- $ref: "#/components/parameters/id"
|
49
|
+
requestBody:
|
50
|
+
description: "Information about updated fields in Team"
|
51
|
+
required: true
|
52
|
+
content:
|
53
|
+
application/json:
|
54
|
+
schema:
|
55
|
+
type: object
|
56
|
+
properties:
|
57
|
+
team:
|
58
|
+
type: object
|
59
|
+
$ref: "#/components/schemas/TeamParameters"
|
47
60
|
responses:
|
48
61
|
"404":
|
49
62
|
description: "Not Found"
|
@@ -52,4 +65,4 @@
|
|
52
65
|
content:
|
53
66
|
application/json:
|
54
67
|
schema:
|
55
|
-
$ref: "#/components/schemas/
|
68
|
+
$ref: "#/components/schemas/TeamAttributes"
|
@@ -4,22 +4,24 @@
|
|
4
4
|
- Users
|
5
5
|
summary: "List Users"
|
6
6
|
operationId: listUsers
|
7
|
+
parameters:
|
8
|
+
- $ref: "#/components/parameters/after"
|
7
9
|
responses:
|
8
10
|
"404":
|
9
11
|
description: "Not Found"
|
10
12
|
"200":
|
11
13
|
description: "OK"
|
14
|
+
headers:
|
15
|
+
Pagination-Next:
|
16
|
+
$ref: "#/components/headers/PaginationNext"
|
17
|
+
Link:
|
18
|
+
$ref: "#/components/headers/Link"
|
12
19
|
content:
|
13
20
|
application/json:
|
14
21
|
schema:
|
15
|
-
type:
|
16
|
-
|
17
|
-
|
18
|
-
type: array
|
19
|
-
items:
|
20
|
-
$ref: "#/components/schemas/UserAttributes"
|
21
|
-
has_more:
|
22
|
-
type: boolean
|
22
|
+
type: array
|
23
|
+
items:
|
24
|
+
$ref: "#/components/schemas/UserAttributes"
|
23
25
|
/users/{id}:
|
24
26
|
get:
|
25
27
|
tags:
|
@@ -44,6 +46,17 @@
|
|
44
46
|
operationId: updateUser
|
45
47
|
parameters:
|
46
48
|
- $ref: "#/components/parameters/id"
|
49
|
+
requestBody:
|
50
|
+
description: "Information about updated fields in User"
|
51
|
+
required: true
|
52
|
+
content:
|
53
|
+
application/json:
|
54
|
+
schema:
|
55
|
+
type: object
|
56
|
+
properties:
|
57
|
+
user:
|
58
|
+
type: object
|
59
|
+
$ref: "#/components/schemas/UserParameters"
|
47
60
|
responses:
|
48
61
|
"404":
|
49
62
|
description: "Not Found"
|
@@ -52,4 +65,4 @@
|
|
52
65
|
content:
|
53
66
|
application/json:
|
54
67
|
schema:
|
55
|
-
$ref: "#/components/schemas/
|
68
|
+
$ref: "#/components/schemas/UserAttributes"
|
@@ -81,6 +81,8 @@ en:
|
|
81
81
|
created: Platform Application was successfully created.
|
82
82
|
updated: Platform Application was successfully updated.
|
83
83
|
destroyed: Platform Application was successfully destroyed.
|
84
|
+
test_application_created: Test Platform Application was successfully created.
|
85
|
+
test_application_failure: You must provide the proper testing provision key to create a test application.
|
84
86
|
account:
|
85
87
|
platform:
|
86
88
|
applications: *applications
|
data/config/routes.rb
CHANGED
@@ -17,6 +17,10 @@ Rails.application.routes.draw do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
if ENV["TESTING_PROVISION_KEY"].present?
|
21
|
+
get "/testing/provision", to: "account/platform/applications#provision"
|
22
|
+
end
|
23
|
+
|
20
24
|
namespace :api do
|
21
25
|
match "*version/openapi.yaml" => "open_api#index", :via => :get
|
22
26
|
|
@@ -1,4 +1,76 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
require "scaffolding"
|
2
|
+
require "scaffolding/file_manipulator"
|
3
|
+
|
4
|
+
namespace :bullet_train do
|
5
|
+
namespace :api do
|
6
|
+
desc "Bump the current version of application's API"
|
7
|
+
task :bump_version do
|
8
|
+
# Calculate new version.
|
9
|
+
initializer_content = File.new("config/initializers/api.rb").readline
|
10
|
+
previous_version = initializer_content.scan(/v\d+/).pop
|
11
|
+
new_version = "v#{previous_version.scan(/\d+/).pop.to_i + 1}"
|
12
|
+
|
13
|
+
# Update initializer.
|
14
|
+
File.write("config/initializers/api.rb", initializer_content.gsub(previous_version, new_version))
|
15
|
+
|
16
|
+
[
|
17
|
+
"app/controllers/api/#{new_version}",
|
18
|
+
"app/views/api/#{new_version}",
|
19
|
+
"test/controllers/api/#{new_version}"
|
20
|
+
].each do |dir|
|
21
|
+
Dir.mkdir(dir)
|
22
|
+
end
|
23
|
+
|
24
|
+
files_to_update = [
|
25
|
+
"config/routes/api/#{previous_version}.rb",
|
26
|
+
Dir.glob("app/controllers/api/#{previous_version}/**/*.rb") +
|
27
|
+
Dir.glob("app/views/api/#{previous_version}/**/*.json.jbuilder") +
|
28
|
+
Dir.glob("test/controllers/api/#{previous_version}/**/*.rb")
|
29
|
+
].flatten
|
30
|
+
|
31
|
+
files_to_update.each do |file_name|
|
32
|
+
previous_file_contents = File.open(file_name).readlines
|
33
|
+
new_file_name = file_name.gsub(previous_version, new_version)
|
34
|
+
|
35
|
+
updated_file_contents = previous_file_contents.map do |line|
|
36
|
+
if line.match?(previous_version)
|
37
|
+
line.gsub(previous_version, new_version)
|
38
|
+
else
|
39
|
+
line.gsub("Api::#{previous_version.upcase}", "Api::#{new_version.upcase}")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# We can't create new files unless each directory under #{api/previous_version}
|
44
|
+
# has been created under the new api directory. For example, we have to create
|
45
|
+
# the `projects` directory before we can create the file `api/v2/projects/pages.json.jbuilder.`
|
46
|
+
new_version_dir, dir_hierarchy = new_file_name.split(/(?<=#{new_version})\//)
|
47
|
+
if dir_hierarchy.present? && dir_hierarchy.match?("/")
|
48
|
+
dir_hierarchy = dir_hierarchy.split("/")
|
49
|
+
dir_hierarchy.inject(new_version_dir) do |base, child_dir_or_file|
|
50
|
+
# Stop making new directories if the string has an extention like ".rb"
|
51
|
+
break if child_dir_or_file.match?(/\./)
|
52
|
+
|
53
|
+
new_hierarchy = "#{base}/#{child_dir_or_file}"
|
54
|
+
Dir.mkdir(new_hierarchy) unless Dir.exist?(new_hierarchy)
|
55
|
+
new_hierarchy
|
56
|
+
end
|
57
|
+
end
|
58
|
+
Scaffolding::FileManipulator.write(new_file_name, updated_file_contents)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Here we make sure config/api/#{new_version}.rb is called from within the main routes file.
|
62
|
+
previous_file_contents = File.open("config/routes.rb").readlines
|
63
|
+
updated_file_contents = previous_file_contents.map do |line|
|
64
|
+
if line.match?("draw \"api/#{previous_version}\"")
|
65
|
+
new_version_draw_line = line.gsub(previous_version, new_version)
|
66
|
+
line + new_version_draw_line
|
67
|
+
else
|
68
|
+
line
|
69
|
+
end
|
70
|
+
end
|
71
|
+
Scaffolding::FileManipulator.write("config/routes.rb", updated_file_contents)
|
72
|
+
|
73
|
+
puts "Finished bumping to #{new_version}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
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.1
|
4
|
+
version: 1.2.1
|
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-
|
11
|
+
date: 2022-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: standard
|