bullet_train-api 1.0.0
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +8 -0
- data/app/assets/config/bullet_train_api_manifest.js +0 -0
- data/app/controllers/account/platform/applications_controller.rb +78 -0
- data/app/controllers/api/v1/defaults.rb +36 -0
- data/app/controllers/api/v1/exceptions_handler.rb +50 -0
- data/app/controllers/api/v1/loads_and_authorizes_api_resource.rb +42 -0
- data/app/controllers/api/v1/me_endpoint.rb +8 -0
- data/app/controllers/api/v1/root.rb +27 -0
- data/app/controllers/api/v1/teams_endpoint.rb +79 -0
- data/app/controllers/api/v1.rb +4 -0
- data/app/models/platform/application.rb +51 -0
- data/app/views/account/platform/applications/_application.json.jbuilder +10 -0
- data/app/views/account/platform/applications/_breadcrumbs.html.erb +8 -0
- data/app/views/account/platform/applications/_form.html.erb +20 -0
- data/app/views/account/platform/applications/_index.html.erb +64 -0
- data/app/views/account/platform/applications/_menu_item.html.erb +10 -0
- data/app/views/account/platform/applications/edit.html.erb +12 -0
- data/app/views/account/platform/applications/index.html.erb +6 -0
- data/app/views/account/platform/applications/index.json.jbuilder +1 -0
- data/app/views/account/platform/applications/new.html.erb +12 -0
- data/app/views/account/platform/applications/show.html.erb +31 -0
- data/app/views/account/platform/applications/show.json.jbuilder +1 -0
- data/config/locales/en/api.en.yml +13 -0
- data/config/locales/en/platform/applications.en.yml +103 -0
- data/config/routes.rb +2 -0
- data/lib/bullet_train/api/engine.rb +6 -0
- data/lib/bullet_train/api/version.rb +5 -0
- data/lib/bullet_train/api.rb +8 -0
- data/lib/tasks/bullet_train/api_tasks.rake +4 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e1a328cffebe8bbf05bf9d14df56afe1142c64cae544f63cc2a306fa1b999cd8
|
4
|
+
data.tar.gz: 6e0d56ea3c25db247665f92b2c443ab027ad2a14540307ae0e938b4a9ad890cd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 417fb8b614b5a43313c63f1c12572a5ce26eb604412d04deccade31ba27b22974dd32c08791cb1aba0b5397ddba59d94874a131af11e77ea61080875dc85442c
|
7
|
+
data.tar.gz: dc17c6b4d31ef02c167da2f69262794960e7cd4e1d8bc96142109262c9326a73f7e0cb77998a6854df0eb0cb2c87f1119f4a6ba257c9675beed3a2b487997ca7
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2022 Andrew Culver
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# BulletTrain::Api
|
2
|
+
Short description and motivation.
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
How to use my plugin.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem "bullet_train-api"
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```bash
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
```bash
|
21
|
+
$ gem install bullet_train-api
|
22
|
+
```
|
23
|
+
|
24
|
+
## Contributing
|
25
|
+
Contribution directions go here.
|
26
|
+
|
27
|
+
## License
|
28
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
File without changes
|
@@ -0,0 +1,78 @@
|
|
1
|
+
class Account::Platform::ApplicationsController < Account::ApplicationController
|
2
|
+
account_load_and_authorize_resource :application, through: :team, through_association: :platform_applications
|
3
|
+
|
4
|
+
# GET /account/teams/:team_id/platform/applications
|
5
|
+
# GET /account/teams/:team_id/platform/applications.json
|
6
|
+
def index
|
7
|
+
# if you only want these objects shown on their parent's show page, uncomment this:
|
8
|
+
# redirect_to [:account, @team]
|
9
|
+
end
|
10
|
+
|
11
|
+
# GET /account/platform/applications/:id
|
12
|
+
# GET /account/platform/applications/:id.json
|
13
|
+
def show
|
14
|
+
end
|
15
|
+
|
16
|
+
# GET /account/teams/:team_id/platform/applications/new
|
17
|
+
def new
|
18
|
+
end
|
19
|
+
|
20
|
+
# GET /account/platform/applications/:id/edit
|
21
|
+
def edit
|
22
|
+
end
|
23
|
+
|
24
|
+
# POST /account/teams/:team_id/platform/applications
|
25
|
+
# POST /account/teams/:team_id/platform/applications.json
|
26
|
+
def create
|
27
|
+
respond_to do |format|
|
28
|
+
if @application.save
|
29
|
+
format.html { redirect_to [:account, @team, :platform_applications], notice: I18n.t("platform/applications.notifications.created") }
|
30
|
+
format.json { render :show, status: :created, location: [:account, @application] }
|
31
|
+
else
|
32
|
+
format.html { render :new, status: :unprocessable_entity }
|
33
|
+
format.json { render json: @application.errors, status: :unprocessable_entity }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# PATCH/PUT /account/platform/applications/:id
|
39
|
+
# PATCH/PUT /account/platform/applications/:id.json
|
40
|
+
def update
|
41
|
+
respond_to do |format|
|
42
|
+
if @application.update(application_params)
|
43
|
+
format.html { redirect_to [:account, @application], notice: I18n.t("platform/applications.notifications.updated") }
|
44
|
+
format.json { render :show, status: :ok, location: [:account, @application] }
|
45
|
+
else
|
46
|
+
format.html { render :edit, status: :unprocessable_entity }
|
47
|
+
format.json { render json: @application.errors, status: :unprocessable_entity }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# DELETE /account/platform/applications/:id
|
53
|
+
# DELETE /account/platform/applications/:id.json
|
54
|
+
def destroy
|
55
|
+
@application.destroy
|
56
|
+
respond_to do |format|
|
57
|
+
format.html { redirect_to [:account, @team, :platform_applications], notice: I18n.t("platform/applications.notifications.destroyed") }
|
58
|
+
format.json { head :no_content }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# Never trust parameters from the scary internet, only allow the white list through.
|
65
|
+
def application_params
|
66
|
+
strong_params = params.require(:platform_application).permit(
|
67
|
+
:name,
|
68
|
+
:scopes,
|
69
|
+
:redirect_uri,
|
70
|
+
# 🚅 super scaffolding will insert new fields above this line.
|
71
|
+
# 🚅 super scaffolding will insert new arrays above this line.
|
72
|
+
)
|
73
|
+
|
74
|
+
# 🚅 super scaffolding will insert processing for new fields above this line.
|
75
|
+
|
76
|
+
strong_params
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Api::V1::Defaults
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
before do
|
6
|
+
header["Access-Control-Allow-Origin"] = "*"
|
7
|
+
header["Access-Control-Request-Method"] = "*"
|
8
|
+
end
|
9
|
+
|
10
|
+
helpers do
|
11
|
+
def current_token
|
12
|
+
doorkeeper_access_token
|
13
|
+
end
|
14
|
+
|
15
|
+
def current_user
|
16
|
+
resource_owner
|
17
|
+
end
|
18
|
+
|
19
|
+
def current_scopes
|
20
|
+
current_token.scopes
|
21
|
+
end
|
22
|
+
|
23
|
+
def current_team
|
24
|
+
current_user.current_team
|
25
|
+
end
|
26
|
+
|
27
|
+
def current_membership
|
28
|
+
current_user.memberships.where(team: current_team).first
|
29
|
+
end
|
30
|
+
|
31
|
+
def current_locale
|
32
|
+
current_user.locale || current_team.locale || "en"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Api::V1::ExceptionsHandler
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
helpers do
|
6
|
+
def record_not_saved(model)
|
7
|
+
handle_api_error(ActiveRecord::RecordNotSaved.new(model.errors.full_messages.first), :unprocessable_entity)
|
8
|
+
end
|
9
|
+
|
10
|
+
def handle_api_error(error, status = nil)
|
11
|
+
error!("Something rather unexpected has occurred", 500) unless error
|
12
|
+
|
13
|
+
error_class = error.class.name
|
14
|
+
status_code = convert_status_symbol_to_integer(status) if status # allows an explicit status to be defined
|
15
|
+
|
16
|
+
message = error.message # works fine for most errors
|
17
|
+
message = "OAuth error: #{error}" if /WineBouncer::Errors/.match?(error_class)
|
18
|
+
message = "Route error: #{error}" if /CanCan::AccessDenied/.match?(error_class)
|
19
|
+
|
20
|
+
if /OAuthUnauthorizedError/.match?(error_class)
|
21
|
+
error!(message, status_code || 401) # unauthorized
|
22
|
+
elsif /OAuthForbiddenError/.match?(error_class) || /CanCan::AccessDenied/.match?(error_class)
|
23
|
+
error!(message, status_code || 403) # forbidden
|
24
|
+
elsif /RecordNotFound/.match?(error_class) || /unable to find/i.match?(message)
|
25
|
+
error!(message, status_code || 404) # not found
|
26
|
+
elsif /Grape::Exceptions::ValidationErrors/.match?(error_class)
|
27
|
+
error!(message, status_code || 406) # not acceptable
|
28
|
+
else
|
29
|
+
Rails.logger.error message unless Rails.env.test?
|
30
|
+
|
31
|
+
options = {error: message}
|
32
|
+
options[:trace] = error.backtrace[0, 10] unless Rails.env.production?
|
33
|
+
|
34
|
+
status_code = status_code || error.try(:status) || 500 # internal server error
|
35
|
+
|
36
|
+
Rack::Response.new(options.to_json, status_code, {
|
37
|
+
"Content-Type" => "application/json",
|
38
|
+
"Access-Control-Allow-Origin" => "*",
|
39
|
+
"Access-Control-Request-Method" => "*"
|
40
|
+
}).finish
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def convert_status_symbol_to_integer(status)
|
45
|
+
# defaults to an internal server error if the status code can't be found
|
46
|
+
Rack::Utils::SYMBOL_TO_STATUS_CODE[status] || 500
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Api::V1::LoadsAndAuthorizesApiResource
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
helpers do
|
6
|
+
def load_and_authorize_api_resource(api_resource_class)
|
7
|
+
raise unless api_resource_class.present?
|
8
|
+
|
9
|
+
instance_variable_name = "@#{api_resource_class.name.demodulize.underscore}"
|
10
|
+
instance_variable_collection_name = instance_variable_name.pluralize
|
11
|
+
|
12
|
+
options = route.settings[:api_resource_options] || {permission: :read, skip_authorize: false}
|
13
|
+
|
14
|
+
permission = options[:permission]
|
15
|
+
skip_authorize = options[:skip_authorize]
|
16
|
+
|
17
|
+
api_resource_params = declared(params, include_missing: false)
|
18
|
+
api_resource_param_id = api_resource_params[:id]
|
19
|
+
api_resource_params_other_ids = api_resource_params.select { |param, value|
|
20
|
+
/_id$/i.match?(param)
|
21
|
+
}
|
22
|
+
|
23
|
+
all_accessible_api_resources = api_resource_class.accessible_by(current_ability, permission)
|
24
|
+
|
25
|
+
if api_resource_param_id.present? # :read, :update, :delete
|
26
|
+
instance_variable_set(instance_variable_name, all_accessible_api_resources.find(api_resource_param_id))
|
27
|
+
elsif permission.eql? :create
|
28
|
+
instance_variable_set(instance_variable_name, api_resource_class.new(api_resource_params))
|
29
|
+
elsif permission.eql? :read
|
30
|
+
all_accessible_api_resources = all_accessible_api_resources.where(api_resource_params_other_ids) if api_resource_params_other_ids.present?
|
31
|
+
instance_variable_set(instance_variable_collection_name, all_accessible_api_resources)
|
32
|
+
skip_authorize = true # can't use CanCan to authorize collections
|
33
|
+
end
|
34
|
+
|
35
|
+
eval "authorize! :#{permission}, #{instance_variable_name}" unless skip_authorize
|
36
|
+
rescue ActiveRecord::RecordNotFound
|
37
|
+
# the default RecordNotFound message includes the raw SQL... which feels bad
|
38
|
+
handle_api_error(ActiveRecord::RecordNotFound.new("The id #{api_resource_param_id} could not be found."))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Api::V1::Root < Api::Base
|
2
|
+
include Api::V1::Defaults
|
3
|
+
include Api::V1::LoadsAndAuthorizesApiResource
|
4
|
+
|
5
|
+
version "v1"
|
6
|
+
use ::WineBouncer::OAuth2
|
7
|
+
|
8
|
+
rescue_from :all do |error|
|
9
|
+
handle_api_error(error)
|
10
|
+
end
|
11
|
+
|
12
|
+
unless scaffolding_things_disabled?
|
13
|
+
mount Api::V1::Scaffolding::AbsolutelyAbstract::CreativeConceptsEndpoint
|
14
|
+
mount Api::V1::Scaffolding::CompletelyConcrete::TangibleThingsEndpoint
|
15
|
+
end
|
16
|
+
|
17
|
+
mount Api::V1::MeEndpoint
|
18
|
+
mount Api::V1::TeamsEndpoint
|
19
|
+
mount Api::V1::Webhooks::Outgoing::EndpointsEndpoint
|
20
|
+
mount Api::V1::Webhooks::Outgoing::DeliveriesEndpoint
|
21
|
+
mount Api::V1::Webhooks::Outgoing::DeliveryAttemptsEndpoint
|
22
|
+
# 🚅 super scaffolding will mount new endpoints above this line.
|
23
|
+
|
24
|
+
route :any, "*path" do
|
25
|
+
raise StandardError, "Unable to find API endpoint"
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class Api::V1::TeamsEndpoint < Api::V1::Root
|
2
|
+
helpers do
|
3
|
+
params :id do
|
4
|
+
requires :id, type: Integer, allow_blank: false, desc: Api.heading(:id)
|
5
|
+
end
|
6
|
+
|
7
|
+
params :team do
|
8
|
+
optional :name, type: String, allow_blank: false, desc: Api.heading(:name)
|
9
|
+
optional :locale, type: String, desc: Api.heading(:locale)
|
10
|
+
# 🚅 super scaffolding will insert new fields above this line.
|
11
|
+
# 🚅 super scaffolding will insert new arrays above this line.
|
12
|
+
|
13
|
+
# 🚅 super scaffolding will insert processing for new fields above this line.
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
resource :teams, desc: Api.title(:actions) do
|
18
|
+
after_validation do
|
19
|
+
load_and_authorize_api_resource Team
|
20
|
+
end
|
21
|
+
|
22
|
+
desc Api.title(:index), &Api.index_desc
|
23
|
+
oauth2
|
24
|
+
paginate per_page: 100
|
25
|
+
get "/" do
|
26
|
+
@paginated_teams = paginate @teams
|
27
|
+
render @paginated_teams, serializer: Api.serializer, adapter: :attributes
|
28
|
+
end
|
29
|
+
|
30
|
+
desc Api.title(:show), &Api.show_desc
|
31
|
+
params do
|
32
|
+
use :id
|
33
|
+
end
|
34
|
+
oauth2
|
35
|
+
route_param :id do
|
36
|
+
get do
|
37
|
+
render @team, serializer: Api.serializer
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
desc Api.title(:create), &Api.create_desc
|
42
|
+
params do
|
43
|
+
use :team
|
44
|
+
end
|
45
|
+
route_setting :api_resource_options, permission: :create
|
46
|
+
oauth2 "write"
|
47
|
+
post "/" do
|
48
|
+
if @team.save
|
49
|
+
# sets the team creator as the default admin
|
50
|
+
@team.memberships.create(user: current_user, roles: [Role.admin])
|
51
|
+
|
52
|
+
current_user.current_team = @team
|
53
|
+
current_user.former_user = false
|
54
|
+
current_user.save
|
55
|
+
|
56
|
+
render @team, serializer: Api.serializer
|
57
|
+
else
|
58
|
+
record_not_saved @team
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
desc Api.title(:update), &Api.update_desc
|
63
|
+
params do
|
64
|
+
use :id
|
65
|
+
use :team
|
66
|
+
end
|
67
|
+
route_setting :api_resource_options, permission: :update
|
68
|
+
oauth2 "write"
|
69
|
+
route_param :id do
|
70
|
+
put do
|
71
|
+
if @team.update(declared(params, include_missing: false))
|
72
|
+
render @team, serializer: Api.serializer
|
73
|
+
else
|
74
|
+
record_not_saved @team
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class Platform::Application < ApplicationRecord
|
2
|
+
self.table_name = "oauth_applications"
|
3
|
+
|
4
|
+
include Doorkeeper::Orm::ActiveRecord::Mixins::Application
|
5
|
+
# 🚅 add concerns above.
|
6
|
+
|
7
|
+
belongs_to :team
|
8
|
+
# 🚅 add belongs_to associations above.
|
9
|
+
|
10
|
+
# 🚅 add has_many associations above.
|
11
|
+
|
12
|
+
# 🚅 add oauth providers above.
|
13
|
+
|
14
|
+
has_one :membership, foreign_key: :platform_agent_of_id, dependent: :nullify
|
15
|
+
has_one :user, foreign_key: :platform_agent_of_id
|
16
|
+
# 🚅 add has_one associations above.
|
17
|
+
|
18
|
+
# 🚅 add scopes above.
|
19
|
+
|
20
|
+
# 🚅 add validations above.
|
21
|
+
|
22
|
+
after_create :create_user_and_membership
|
23
|
+
after_update :update_user_and_membership
|
24
|
+
before_destroy :destroy_user
|
25
|
+
# 🚅 add callbacks above.
|
26
|
+
|
27
|
+
# 🚅 add delegations above.
|
28
|
+
|
29
|
+
def label_string
|
30
|
+
name
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_user_and_membership
|
34
|
+
faux_password = SecureRandom.hex
|
35
|
+
create_user(email: "noreply+#{SecureRandom.hex}@bullettrain.co", password: faux_password, password_confirmation: faux_password, first_name: label_string)
|
36
|
+
create_membership(team: team, user: user)
|
37
|
+
membership.roles << Role.admin
|
38
|
+
end
|
39
|
+
|
40
|
+
def update_user_and_membership
|
41
|
+
user.update(first_name: label_string)
|
42
|
+
end
|
43
|
+
|
44
|
+
def destroy_user
|
45
|
+
former_user = membership.user
|
46
|
+
membership.nullify_user
|
47
|
+
former_user.destroy
|
48
|
+
end
|
49
|
+
|
50
|
+
# 🚅 add methods above.
|
51
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<% application ||= @application %>
|
2
|
+
<% team ||= @team || application&.team %>
|
3
|
+
<%= render 'account/teams/breadcrumbs', team: team %>
|
4
|
+
<%= render 'account/shared/breadcrumb', label: t('.label'), url: [:account, team, :platform_applications] %>
|
5
|
+
<% if application&.persisted? %>
|
6
|
+
<%= render 'account/shared/breadcrumb', label: application.label_string, url: [:account, application] %>
|
7
|
+
<% end %>
|
8
|
+
<%= render 'account/shared/breadcrumbs/actions', only_for: 'platform/applications' %>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<%= form_with model: application, url: (application.persisted? ? [:account, application] : [:account, @team, :platform_applications]), local: true, class: 'form' do |form| %>
|
2
|
+
<%= render 'account/shared/forms/errors', form: form %>
|
3
|
+
|
4
|
+
<% with_field_settings form: form do %>
|
5
|
+
<%= render 'shared/fields/text_field', method: :name, options: {autofocus: true} %>
|
6
|
+
<%= render 'shared/fields/text_field', method: :scopes %>
|
7
|
+
<%= render 'shared/fields/text_field', method: :redirect_uri %>
|
8
|
+
<%# 🚅 super scaffolding will insert new fields above this line. %>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<div class="buttons">
|
12
|
+
<%= form.submit (form.object.persisted? ? t('.buttons.update') : t('.buttons.create')), class: "button" %>
|
13
|
+
<% if form.object.persisted? %>
|
14
|
+
<%= link_to t('global.buttons.cancel'), [:account, application], class: "button-secondary" %>
|
15
|
+
<% else %>
|
16
|
+
<%= link_to t('global.buttons.cancel'), [:account, @team, :platform_applications], class: "button-secondary" %>
|
17
|
+
<% end %>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<% end %>
|
@@ -0,0 +1,64 @@
|
|
1
|
+
<% team = @team || @team %>
|
2
|
+
<% context ||= team %>
|
3
|
+
<% collection ||= :platform_applications %>
|
4
|
+
<% hide_actions ||= false %>
|
5
|
+
<% hide_back ||= false %>
|
6
|
+
|
7
|
+
<%= render 'account/shared/box' do |p| %>
|
8
|
+
<% p.content_for :title, t(".contexts.#{context.class.name.underscore}.header") %>
|
9
|
+
<% p.content_for :description do %>
|
10
|
+
<%= t(".contexts.#{context.class.name.underscore}.description#{"_empty" unless applications.any?}") %>
|
11
|
+
<% end %>
|
12
|
+
|
13
|
+
<% p.content_for :table do %>
|
14
|
+
<% if applications.any? %>
|
15
|
+
<table class="table">
|
16
|
+
<thead>
|
17
|
+
<tr>
|
18
|
+
<th><%= t('.fields.name.heading') %></th>
|
19
|
+
<th><%= t('.fields.scopes.heading') %></th>
|
20
|
+
<%# 🚅 super scaffolding will insert new field headers above this line. %>
|
21
|
+
<th><%= t('.fields.created_at.heading') %></th>
|
22
|
+
<th class="text-right"></th>
|
23
|
+
</tr>
|
24
|
+
</thead>
|
25
|
+
<tbody>
|
26
|
+
<% applications.each do |application| %>
|
27
|
+
<% with_attribute_settings object: application do %>
|
28
|
+
<tr data-id="<%= application.id %>">
|
29
|
+
<td><%= render 'shared/attributes/text', attribute: :name, url: [:account, application] %></td>
|
30
|
+
<td><%= render 'shared/attributes/text', attribute: :scopes %></td>
|
31
|
+
<%# 🚅 super scaffolding will insert new fields above this line. %>
|
32
|
+
<td><%= display_date_and_time(application.created_at) %></td>
|
33
|
+
<td class="buttons">
|
34
|
+
<% unless hide_actions %>
|
35
|
+
<% if can? :edit, application %>
|
36
|
+
<%= link_to t('.buttons.shorthand.edit'), [:edit, :account, application], class: 'button-secondary button-smaller' %>
|
37
|
+
<% end %>
|
38
|
+
<% if can? :destroy, application %>
|
39
|
+
<%= button_to t('.buttons.shorthand.destroy'), [:account, application], method: :delete, data: { confirm: t('.buttons.confirmations.destroy', model_locales(application)) }, class: 'button-secondary button-smaller' %>
|
40
|
+
<% end %>
|
41
|
+
<% end %>
|
42
|
+
</td>
|
43
|
+
</tr>
|
44
|
+
<% end %>
|
45
|
+
<% end %>
|
46
|
+
</tbody>
|
47
|
+
</table>
|
48
|
+
<% end %>
|
49
|
+
<% end %>
|
50
|
+
|
51
|
+
<% p.content_for :actions do %>
|
52
|
+
<% unless hide_actions %>
|
53
|
+
<% if context == team %>
|
54
|
+
<% if can? :create, Platform::Application.new(team: team) %>
|
55
|
+
<%= link_to t('.buttons.new'), [:new, :account, team, :platform_application], class: "#{first_button_primary(:platform_application)} new" %>
|
56
|
+
<% end %>
|
57
|
+
<% end %>
|
58
|
+
|
59
|
+
<% unless hide_back %>
|
60
|
+
<%= link_to t('global.buttons.back'), [:account, context], class: "#{first_button_primary(:platform_application)} back" %>
|
61
|
+
<% end %>
|
62
|
+
<% end %>
|
63
|
+
<% end %>
|
64
|
+
<% end %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<% if can? :read, Platform::Application.new(team: current_team) %>
|
2
|
+
<%= render 'account/shared/menu/item', {
|
3
|
+
url: main_app.polymorphic_path([:account, current_team, :platform_applications]),
|
4
|
+
label: t('platform/applications.navigation.label'),
|
5
|
+
} do |p| %>
|
6
|
+
<% p.content_for :icon do %>
|
7
|
+
<i class="<%= t('platform/applications.navigation.icon') %>"></i>
|
8
|
+
<% end %>
|
9
|
+
<% end %>
|
10
|
+
<% end %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<%= render 'account/shared/page' do |p| %>
|
2
|
+
<% p.content_for :title, t('.section') %>
|
3
|
+
<% p.content_for :body do %>
|
4
|
+
<%= render 'account/shared/box', divider: true do |p| %>
|
5
|
+
<% p.content_for :title, t('.header') %>
|
6
|
+
<% p.content_for :description, t('.description') %>
|
7
|
+
<% p.content_for :body do %>
|
8
|
+
<%= render 'form', application: @application %>
|
9
|
+
<% end %>
|
10
|
+
<% end %>
|
11
|
+
<% end %>
|
12
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
json.array! @applications, partial: "platform/applications/application", as: :application
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<%= render 'account/shared/page' do |p| %>
|
2
|
+
<% p.content_for :title, t('.section') %>
|
3
|
+
<% p.content_for :body do %>
|
4
|
+
<%= render 'account/shared/box', divider: true do |p| %>
|
5
|
+
<% p.content_for :title, t('.header') %>
|
6
|
+
<% p.content_for :description, t('.description') %>
|
7
|
+
<% p.content_for :body do %>
|
8
|
+
<%= render 'form', application: @application %>
|
9
|
+
<% end %>
|
10
|
+
<% end %>
|
11
|
+
<% end %>
|
12
|
+
<% end %>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<%= render 'account/shared/page' do |p| %>
|
2
|
+
<% p.content_for :title, t('.section') %>
|
3
|
+
<% p.content_for :body do %>
|
4
|
+
<%= render 'account/shared/box', divider: true do |p| %>
|
5
|
+
<% p.content_for :title, t('.header') %>
|
6
|
+
<% p.content_for :description do %>
|
7
|
+
<%= t('.description') %>
|
8
|
+
<%= t('.manage_description') if can? :manage, @application %>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<% p.content_for :body do %>
|
12
|
+
<% with_attribute_settings object: @application, strategy: :label do %>
|
13
|
+
<%= render 'shared/attributes/text', attribute: :name %>
|
14
|
+
<%= render 'shared/attributes/code', attribute: :uid %>
|
15
|
+
<%= render 'shared/attributes/code', attribute: :secret %>
|
16
|
+
<%= render 'shared/attributes/text', attribute: :scopes %>
|
17
|
+
<%= render 'shared/attributes/text', attribute: :redirect_uri %>
|
18
|
+
<%# 🚅 super scaffolding will insert new fields above this line. %>
|
19
|
+
<% end %>
|
20
|
+
<% end %>
|
21
|
+
|
22
|
+
<% p.content_for :actions do %>
|
23
|
+
<%= link_to t('.buttons.edit'), [:edit, :account, @application], class: first_button_primary if can? :edit, @application %>
|
24
|
+
<%= button_to t('.buttons.destroy'), [:account, @application], method: :delete, class: first_button_primary, data: { confirm: t('.buttons.confirmations.destroy', model_locales(@application)) } if can? :destroy, @application %>
|
25
|
+
<%= link_to t('global.buttons.back'), [:account, @team, :platform_applications], class: first_button_primary %>
|
26
|
+
<% end %>
|
27
|
+
<% end %>
|
28
|
+
|
29
|
+
<%# 🚅 super scaffolding will insert new children above this line. %>
|
30
|
+
<% end %>
|
31
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
json.partial! "platform/applications/application", application: @application
|
@@ -0,0 +1,13 @@
|
|
1
|
+
en:
|
2
|
+
api:
|
3
|
+
statuses:
|
4
|
+
200: "Success" # okay
|
5
|
+
201: "Success" # created
|
6
|
+
400: "Missing or Bad Parameters" # bad request
|
7
|
+
401: "Not Authorized" # unauthorized
|
8
|
+
403: "Permission Denied" # forbidden
|
9
|
+
404: "Record Not Found" # not found
|
10
|
+
406: "Validation Errors" # not acceptable
|
11
|
+
422: "Record Not Saved" # unprocessable entity
|
12
|
+
429: "API Rate Limit Exceeded" # too many requests
|
13
|
+
500: "Internal Server Error" # internal server error
|
@@ -0,0 +1,103 @@
|
|
1
|
+
en:
|
2
|
+
platform/applications: &applications
|
3
|
+
label: &label Platform Applications
|
4
|
+
breadcrumbs:
|
5
|
+
label: *label
|
6
|
+
navigation:
|
7
|
+
label: Your Applications
|
8
|
+
icon: fal fa-browser ti ti-plug
|
9
|
+
buttons: &buttons
|
10
|
+
new: Add New Platform Application
|
11
|
+
create: Provision Platform Application
|
12
|
+
edit: Edit Platform Application
|
13
|
+
update: Update Platform Application
|
14
|
+
destroy: Remove Platform Application
|
15
|
+
shorthand:
|
16
|
+
edit: Edit
|
17
|
+
destroy: Delete
|
18
|
+
disconnect: Disconnect
|
19
|
+
confirmations:
|
20
|
+
# TODO customize for your use-case.
|
21
|
+
destroy: Are you sure you want to remove %{application_name}? This will also remove it's associated data. This can't be undone.
|
22
|
+
disconnect: Are you sure you want to disconnect %{application_name}? This might affect an ongoing service provided by %{application_name} and can not be undone.
|
23
|
+
fields: &fields
|
24
|
+
name:
|
25
|
+
_: &name Name
|
26
|
+
label: *name
|
27
|
+
heading: Application Name
|
28
|
+
|
29
|
+
scopes:
|
30
|
+
_: &scopes Scopes
|
31
|
+
label: *scopes
|
32
|
+
heading: *scopes
|
33
|
+
help: Scopes are like permissions. An OAuth application can have read, write, and/or delete access. Separate scopes with spaces. Leave this field blank to use the default scope, e.g. "read". Optional scopes are "write" and "delete".
|
34
|
+
|
35
|
+
redirect_uri:
|
36
|
+
_: &redirect_uri Redirect URI
|
37
|
+
label: *redirect_uri
|
38
|
+
heading: *redirect_uri
|
39
|
+
help: You can leave this field blank.
|
40
|
+
|
41
|
+
uid:
|
42
|
+
heading: Client UID
|
43
|
+
|
44
|
+
secret:
|
45
|
+
heading: Client Secret
|
46
|
+
|
47
|
+
label_string:
|
48
|
+
heading: Application Name
|
49
|
+
|
50
|
+
# 🚅 super scaffolding will insert new fields above this line.
|
51
|
+
created_at:
|
52
|
+
_: &created_at Added
|
53
|
+
label: *created_at
|
54
|
+
heading: *created_at
|
55
|
+
updated_at:
|
56
|
+
_: &updated_at Updated
|
57
|
+
label: *updated_at
|
58
|
+
heading: *updated_at
|
59
|
+
index:
|
60
|
+
section: "%{teams_possessive} Platform Applications"
|
61
|
+
contexts:
|
62
|
+
team:
|
63
|
+
header: Platform Applications
|
64
|
+
description: Below is a list of Platform Applications that have been provisioned for %{team_name}.
|
65
|
+
description_empty: No Platform Applications have been provisioned for %{team_name}.
|
66
|
+
fields: *fields
|
67
|
+
buttons: *buttons
|
68
|
+
show:
|
69
|
+
section: "%{application_name}"
|
70
|
+
header: Platform Application Details
|
71
|
+
description: Below are the details we have for %{application_name}.
|
72
|
+
manage_description: You'll also find options for updating these details or removing %{application_name} from %{team_name} entirely.
|
73
|
+
fields: *fields
|
74
|
+
buttons: *buttons
|
75
|
+
form: &form
|
76
|
+
buttons: *buttons
|
77
|
+
fields: *fields
|
78
|
+
new:
|
79
|
+
section: "New Platform Application for %{team_name}"
|
80
|
+
header: New Platform Application Details
|
81
|
+
description: Please provide the details of the new Platform Application you'd like to provision for %{team_name}.
|
82
|
+
form: *form
|
83
|
+
edit:
|
84
|
+
section: "%{application_name}"
|
85
|
+
header: Edit Platform Application Details
|
86
|
+
description: You can update the details or settings for %{application_name} below.
|
87
|
+
form: *form
|
88
|
+
notifications:
|
89
|
+
created: Platform Application was successfully created.
|
90
|
+
updated: Platform Application was successfully updated.
|
91
|
+
destroyed: Platform Application was successfully destroyed.
|
92
|
+
account:
|
93
|
+
platform:
|
94
|
+
applications: *applications
|
95
|
+
activerecord:
|
96
|
+
attributes:
|
97
|
+
platform/application:
|
98
|
+
name: *name
|
99
|
+
scopes: *scopes
|
100
|
+
redirect_uri: *redirect_uri
|
101
|
+
# 🚅 super scaffolding will insert new activerecord attributes above this line.
|
102
|
+
created_at: *created_at
|
103
|
+
updated_at: *updated_at
|
data/config/routes.rb
ADDED
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bullet_train-api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Culver
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-01-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 7.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 7.0.0
|
27
|
+
description: Bullet Train API
|
28
|
+
email:
|
29
|
+
- andrew.culver@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- MIT-LICENSE
|
35
|
+
- README.md
|
36
|
+
- Rakefile
|
37
|
+
- app/assets/config/bullet_train_api_manifest.js
|
38
|
+
- app/controllers/account/platform/applications_controller.rb
|
39
|
+
- app/controllers/api/v1.rb
|
40
|
+
- app/controllers/api/v1/defaults.rb
|
41
|
+
- app/controllers/api/v1/exceptions_handler.rb
|
42
|
+
- app/controllers/api/v1/loads_and_authorizes_api_resource.rb
|
43
|
+
- app/controllers/api/v1/me_endpoint.rb
|
44
|
+
- app/controllers/api/v1/root.rb
|
45
|
+
- app/controllers/api/v1/teams_endpoint.rb
|
46
|
+
- app/models/platform/application.rb
|
47
|
+
- app/views/account/platform/applications/_application.json.jbuilder
|
48
|
+
- app/views/account/platform/applications/_breadcrumbs.html.erb
|
49
|
+
- app/views/account/platform/applications/_form.html.erb
|
50
|
+
- app/views/account/platform/applications/_index.html.erb
|
51
|
+
- app/views/account/platform/applications/_menu_item.html.erb
|
52
|
+
- app/views/account/platform/applications/edit.html.erb
|
53
|
+
- app/views/account/platform/applications/index.html.erb
|
54
|
+
- app/views/account/platform/applications/index.json.jbuilder
|
55
|
+
- app/views/account/platform/applications/new.html.erb
|
56
|
+
- app/views/account/platform/applications/show.html.erb
|
57
|
+
- app/views/account/platform/applications/show.json.jbuilder
|
58
|
+
- config/locales/en/api.en.yml
|
59
|
+
- config/locales/en/platform/applications.en.yml
|
60
|
+
- config/routes.rb
|
61
|
+
- lib/bullet_train/api.rb
|
62
|
+
- lib/bullet_train/api/engine.rb
|
63
|
+
- lib/bullet_train/api/version.rb
|
64
|
+
- lib/tasks/bullet_train/api_tasks.rake
|
65
|
+
homepage: https://github.com/bullet-train-co/bullet_train-api
|
66
|
+
licenses:
|
67
|
+
- MIT
|
68
|
+
metadata:
|
69
|
+
homepage_uri: https://github.com/bullet-train-co/bullet_train-api
|
70
|
+
source_code_uri: https://github.com/bullet-train-co/bullet_train-api
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubygems_version: 3.2.22
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: Bullet Train API
|
90
|
+
test_files: []
|