bullet_train-api 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|