bullet_train-api 1.0.17 → 1.1.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 +4 -4
- data/config/routes.rb +1 -1
- data/lib/bullet_train/api/engine.rb +0 -13
- data/lib/bullet_train/api/version.rb +1 -1
- data/lib/bullet_train/api.rb +2 -7
- metadata +5 -109
- data/app/controllers/api/base.rb +0 -31
- data/app/controllers/api/model_parser.rb +0 -42
- data/app/controllers/api/v1/defaults.rb +0 -36
- data/app/controllers/api/v1/exceptions_handler.rb +0 -50
- data/app/controllers/api/v1/loads_and_authorizes_api_resource.rb +0 -42
- data/app/controllers/api/v1/me_endpoint.rb +0 -9
- data/app/controllers/api/v1/teams_endpoint.rb +0 -9
- data/app/controllers/api/v1.rb +0 -4
- data/app/controllers/api.rb +0 -96
- data/app/controllers/concerns/api/v1/base.rb +0 -37
- data/app/controllers/concerns/api/v1/teams/endpoint_base.rb +0 -87
- data/app/serializers/api/v1/invitation_serializer.rb +0 -8
- data/app/serializers/api/v1/me_serializer.rb +0 -4
- data/app/serializers/api/v1/membership_serializer.rb +0 -8
- data/app/serializers/api/v1/team_serializer.rb +0 -8
- data/app/serializers/api/v1/user_serializer.rb +0 -8
- data/app/serializers/concerns/api/v1/invitations/serializer_base.rb +0 -17
- data/app/serializers/concerns/api/v1/memberships/serializer_base.rb +0 -24
- data/app/serializers/concerns/api/v1/teams/serializer_base.rb +0 -16
- data/app/serializers/concerns/api/v1/users/serializer_base.rb +0 -22
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7aa6663e2cb44dcb5ee04f1523126af49e244a71168c4be2e4b5333ef957890f
|
|
4
|
+
data.tar.gz: 6efa8a9d4538ff0a031fba1bbdd8dfa5fdef35f099be7e1045766cb760ca1fed
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 89cd48b2f9291e06563533ee36d7081176a82ffa97e7c62096477c5cfa97501f83b7f0d1f34bad3d52f22a2b910e75789a320c60e0196b0df4c7073045444a21
|
|
7
|
+
data.tar.gz: c75051c39a212d6994a7b19ed4fb1df756927d5599c4d2b8e92330855b4cb08e1d7ff5a884902d793d6b878c1d37d77153db3dfa7173ff1f22801b3ff4f245e2
|
data/config/routes.rb
CHANGED
|
@@ -1,22 +1,9 @@
|
|
|
1
|
-
require "grape"
|
|
2
|
-
require "grape-cancan"
|
|
3
|
-
require "grape_jsonapi"
|
|
4
|
-
require "grape-swagger"
|
|
5
|
-
require "grape_on_rails_routes"
|
|
6
|
-
# require "wine_bouncer"
|
|
7
1
|
require "pagy"
|
|
8
|
-
require "api-pagination"
|
|
9
2
|
require "rack/cors"
|
|
10
3
|
|
|
11
4
|
module BulletTrain
|
|
12
5
|
module Api
|
|
13
6
|
class Engine < ::Rails::Engine
|
|
14
|
-
initializer "bullet_train.api.register_api_endpoints" do |app|
|
|
15
|
-
if BulletTrain::Api
|
|
16
|
-
BulletTrain::Api.endpoints << "Api::V1::MeEndpoint"
|
|
17
|
-
BulletTrain::Api.endpoints << "Api::V1::TeamsEndpoint"
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
7
|
end
|
|
21
8
|
end
|
|
22
9
|
end
|
data/lib/bullet_train/api.rb
CHANGED
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
require "bullet_train/api/version"
|
|
2
2
|
require "bullet_train/api/engine"
|
|
3
3
|
|
|
4
|
-
require "grape"
|
|
5
|
-
require "grape-cancan"
|
|
6
|
-
require "grape_jsonapi"
|
|
7
|
-
require "grape-swagger"
|
|
8
|
-
require "grape_on_rails_routes"
|
|
9
4
|
# require "wine_bouncer"
|
|
10
5
|
require "pagy"
|
|
11
|
-
require "
|
|
6
|
+
require "pagy_cursor"
|
|
12
7
|
require "rack/cors"
|
|
13
|
-
require "jsonapi/serializer"
|
|
14
8
|
require "doorkeeper"
|
|
15
9
|
|
|
16
10
|
module BulletTrain
|
|
17
11
|
module Api
|
|
18
12
|
mattr_accessor :endpoints, default: []
|
|
13
|
+
mattr_accessor :current_version, default: "v1"
|
|
19
14
|
end
|
|
20
15
|
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.0
|
|
4
|
+
version: 1.1.0
|
|
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-09-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: standard
|
|
@@ -30,84 +30,14 @@ dependencies:
|
|
|
30
30
|
requirements:
|
|
31
31
|
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
33
|
+
version: 6.0.0
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
41
|
-
- !ruby/object:Gem::Dependency
|
|
42
|
-
name: grape
|
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
|
44
|
-
requirements:
|
|
45
|
-
- - "~>"
|
|
46
|
-
- !ruby/object:Gem::Version
|
|
47
|
-
version: 1.6.0
|
|
48
|
-
type: :runtime
|
|
49
|
-
prerelease: false
|
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
-
requirements:
|
|
52
|
-
- - "~>"
|
|
53
|
-
- !ruby/object:Gem::Version
|
|
54
|
-
version: 1.6.0
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: grape-cancan
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - ">="
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: '0'
|
|
62
|
-
type: :runtime
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
-
requirements:
|
|
66
|
-
- - ">="
|
|
67
|
-
- !ruby/object:Gem::Version
|
|
68
|
-
version: '0'
|
|
69
|
-
- !ruby/object:Gem::Dependency
|
|
70
|
-
name: grape-jsonapi
|
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
|
72
|
-
requirements:
|
|
73
|
-
- - '='
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: 1.0.0
|
|
76
|
-
type: :runtime
|
|
77
|
-
prerelease: false
|
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
-
requirements:
|
|
80
|
-
- - '='
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: 1.0.0
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: grape-swagger
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - ">="
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '0'
|
|
90
|
-
type: :runtime
|
|
91
|
-
prerelease: false
|
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
-
requirements:
|
|
94
|
-
- - ">="
|
|
95
|
-
- !ruby/object:Gem::Version
|
|
96
|
-
version: '0'
|
|
97
|
-
- !ruby/object:Gem::Dependency
|
|
98
|
-
name: grape_on_rails_routes
|
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
|
100
|
-
requirements:
|
|
101
|
-
- - ">="
|
|
102
|
-
- !ruby/object:Gem::Version
|
|
103
|
-
version: '0'
|
|
104
|
-
type: :runtime
|
|
105
|
-
prerelease: false
|
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
-
requirements:
|
|
108
|
-
- - ">="
|
|
109
|
-
- !ruby/object:Gem::Version
|
|
110
|
-
version: '0'
|
|
40
|
+
version: 6.0.0
|
|
111
41
|
- !ruby/object:Gem::Dependency
|
|
112
42
|
name: pagy
|
|
113
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -123,7 +53,7 @@ dependencies:
|
|
|
123
53
|
- !ruby/object:Gem::Version
|
|
124
54
|
version: '0'
|
|
125
55
|
- !ruby/object:Gem::Dependency
|
|
126
|
-
name:
|
|
56
|
+
name: pagy_cursor
|
|
127
57
|
requirement: !ruby/object:Gem::Requirement
|
|
128
58
|
requirements:
|
|
129
59
|
- - ">="
|
|
@@ -150,20 +80,6 @@ dependencies:
|
|
|
150
80
|
- - ">="
|
|
151
81
|
- !ruby/object:Gem::Version
|
|
152
82
|
version: '0'
|
|
153
|
-
- !ruby/object:Gem::Dependency
|
|
154
|
-
name: jsonapi-serializer
|
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
|
156
|
-
requirements:
|
|
157
|
-
- - ">="
|
|
158
|
-
- !ruby/object:Gem::Version
|
|
159
|
-
version: '0'
|
|
160
|
-
type: :runtime
|
|
161
|
-
prerelease: false
|
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
-
requirements:
|
|
164
|
-
- - ">="
|
|
165
|
-
- !ruby/object:Gem::Version
|
|
166
|
-
version: '0'
|
|
167
83
|
- !ruby/object:Gem::Dependency
|
|
168
84
|
name: doorkeeper
|
|
169
85
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -204,27 +120,7 @@ files:
|
|
|
204
120
|
- Rakefile
|
|
205
121
|
- app/assets/config/bullet_train_api_manifest.js
|
|
206
122
|
- app/controllers/account/platform/applications_controller.rb
|
|
207
|
-
- app/controllers/api.rb
|
|
208
|
-
- app/controllers/api/base.rb
|
|
209
|
-
- app/controllers/api/model_parser.rb
|
|
210
|
-
- app/controllers/api/v1.rb
|
|
211
|
-
- app/controllers/api/v1/defaults.rb
|
|
212
|
-
- app/controllers/api/v1/exceptions_handler.rb
|
|
213
|
-
- app/controllers/api/v1/loads_and_authorizes_api_resource.rb
|
|
214
|
-
- app/controllers/api/v1/me_endpoint.rb
|
|
215
|
-
- app/controllers/api/v1/teams_endpoint.rb
|
|
216
|
-
- app/controllers/concerns/api/v1/base.rb
|
|
217
|
-
- app/controllers/concerns/api/v1/teams/endpoint_base.rb
|
|
218
123
|
- app/models/platform/application.rb
|
|
219
|
-
- app/serializers/api/v1/invitation_serializer.rb
|
|
220
|
-
- app/serializers/api/v1/me_serializer.rb
|
|
221
|
-
- app/serializers/api/v1/membership_serializer.rb
|
|
222
|
-
- app/serializers/api/v1/team_serializer.rb
|
|
223
|
-
- app/serializers/api/v1/user_serializer.rb
|
|
224
|
-
- app/serializers/concerns/api/v1/invitations/serializer_base.rb
|
|
225
|
-
- app/serializers/concerns/api/v1/memberships/serializer_base.rb
|
|
226
|
-
- app/serializers/concerns/api/v1/teams/serializer_base.rb
|
|
227
|
-
- app/serializers/concerns/api/v1/users/serializer_base.rb
|
|
228
124
|
- app/views/account/platform/applications/_application.json.jbuilder
|
|
229
125
|
- app/views/account/platform/applications/_breadcrumbs.html.erb
|
|
230
126
|
- app/views/account/platform/applications/_form.html.erb
|
data/app/controllers/api/base.rb
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
require "grape-swagger"
|
|
2
|
-
require_relative "../api"
|
|
3
|
-
|
|
4
|
-
class Api::Base < Grape::API
|
|
5
|
-
content_type :jsonapi, "application/vnd.api+json"
|
|
6
|
-
formatter :json, Grape::Formatter::Jsonapi
|
|
7
|
-
formatter :jsonapi, Grape::Formatter::Jsonapi
|
|
8
|
-
format :jsonapi
|
|
9
|
-
default_error_formatter :json
|
|
10
|
-
|
|
11
|
-
mount Api::V1::Root
|
|
12
|
-
|
|
13
|
-
# Swagger docs are available at `/api/docs/swagger.json`.
|
|
14
|
-
add_swagger_documentation \
|
|
15
|
-
api_version: "v1",
|
|
16
|
-
array_use_braces: true,
|
|
17
|
-
base_path: "/api",
|
|
18
|
-
doc_version: "1.0",
|
|
19
|
-
endpoint_auth_wrapper: ::WineBouncer::OAuth2,
|
|
20
|
-
hide_documentation_path: true,
|
|
21
|
-
info: {
|
|
22
|
-
title: I18n.t("application.name"),
|
|
23
|
-
description: I18n.t("application.description")
|
|
24
|
-
},
|
|
25
|
-
mount_path: "/docs/swagger"
|
|
26
|
-
|
|
27
|
-
# TODO Reintroduce this once we've got `context` in current attributes.
|
|
28
|
-
# before do
|
|
29
|
-
# Current.context = :api
|
|
30
|
-
# end
|
|
31
|
-
end
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
class Api::ModelParser < GrapeSwagger::Jsonapi::Parser
|
|
2
|
-
attr_reader :model, :endpoint
|
|
3
|
-
|
|
4
|
-
alias_method :schema, :call
|
|
5
|
-
|
|
6
|
-
def initialize(model, endpoint)
|
|
7
|
-
@model = model
|
|
8
|
-
@endpoint = endpoint
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def call
|
|
12
|
-
# first let's grab the schema generated by the JSON:API parser
|
|
13
|
-
schema_json = schema.to_json
|
|
14
|
-
|
|
15
|
-
# From Nick Schneble:
|
|
16
|
-
|
|
17
|
-
# we can easily override these types for our API endpoints in the documentation
|
|
18
|
-
# but we can't do the same thing for the relationship objects that are auto-generated
|
|
19
|
-
# thus the fancy affair below
|
|
20
|
-
|
|
21
|
-
# if you want to learn more about what's happening here, read these:
|
|
22
|
-
# https://stackoverflow.com/a/17918118/1322386
|
|
23
|
-
# https://swagger.io/docs/specification/data-models/data-types/
|
|
24
|
-
|
|
25
|
-
# Swagger 3.0 only supports a subset of Ruby data types
|
|
26
|
-
schema_json.gsub!("\"type\":\"binary\"", "\"type\":\"string\", \"format\":\"binary\"")
|
|
27
|
-
schema_json.gsub!("\"type\":\"date\"", "\"type\":\"string\", \"format\":\"date\"")
|
|
28
|
-
schema_json.gsub!("\"type\":\"datetime\"", "\"type\":\"string\", \"format\":\"date-time\"")
|
|
29
|
-
schema_json.gsub!("\"type\":\"decimal\"", "\"type\":\"number\", \"format\":\"double\"")
|
|
30
|
-
schema_json.gsub!("\"type\":\"float\"", "\"type\":\"number\", \"format\":\"float\"")
|
|
31
|
-
schema_json.gsub!("\"type\":\"bigint\"", "\"type\":\"integer\", \"format\":\"int64\"")
|
|
32
|
-
schema_json.gsub!("\"type\":\"primary_key\"", "\"type\":\"integer\", \"format\":\"int64\"")
|
|
33
|
-
schema_json.gsub!("\"type\":\"references\"", "\"type\":\"object\"")
|
|
34
|
-
schema_json.gsub!("\"type\":\"text\"", "\"type\":\"string\"")
|
|
35
|
-
schema_json.gsub!("\"type\":\"time\"", "\"type\":\"string\", \"format\":\"time\"")
|
|
36
|
-
schema_json.gsub!("\"type\":\"timestamp\"", "\"type\":\"string\", \"format\":\"timestamp\"")
|
|
37
|
-
schema_json.gsub!("\"type\":\"json\"", "\"type\":\"array\", \"items\":{\"type\":\"string\"}")
|
|
38
|
-
|
|
39
|
-
# returns a Hash as if nothing fancy happened
|
|
40
|
-
JSON.parse(schema_json)
|
|
41
|
-
end
|
|
42
|
-
end
|
|
@@ -1,36 +0,0 @@
|
|
|
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
|
|
@@ -1,50 +0,0 @@
|
|
|
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
|
|
@@ -1,42 +0,0 @@
|
|
|
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
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
class Api::V1::MeEndpoint < Api::V1::Root
|
|
2
|
-
resource :me, desc: Api.title(:actions) do
|
|
3
|
-
desc Api.title(:show), &Api.show_desc
|
|
4
|
-
oauth2
|
|
5
|
-
get do
|
|
6
|
-
render current_user, include: [:teams, :memberships], serializer: "Api::V1::UserSerializer", adapter: :attributes
|
|
7
|
-
end
|
|
8
|
-
end
|
|
9
|
-
end
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
class Api::V1::TeamsEndpoint < Api::V1::Root
|
|
2
|
-
PARAMS = proc do
|
|
3
|
-
# 🚅 super scaffolding will insert new fields above this line.
|
|
4
|
-
# 🚅 super scaffolding will insert new arrays above this line.
|
|
5
|
-
# 🚅 super scaffolding will insert processing for new fields above this line.
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
include Api::V1::Teams::EndpointBase
|
|
9
|
-
end
|
data/app/controllers/api/v1.rb
DELETED
data/app/controllers/api.rb
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# We have to do this because there are a couple of different Grape contexts where you're trying to define something
|
|
2
|
-
# for a model's API representation, but the execution context doesn't have access to the endpoint object you're
|
|
3
|
-
# defining things for. I understand the design thinking that caused that situation, but unfortunately for us we just
|
|
4
|
-
# have to brute force our way around it for now. In doing so, we're implementing something not unlike the magic of the
|
|
5
|
-
# `t` helper in Rails views.
|
|
6
|
-
|
|
7
|
-
module Api
|
|
8
|
-
def self.topic
|
|
9
|
-
path = caller.find { |path| (path.include?("controllers/api") || path.include?("app/controllers/concerns/api")) && !path.include?("app/controllers/api.rb") && !path.include?("app/controllers/api/v1/root.rb") && !path.include?("app/controllers/api/base.rb") }
|
|
10
|
-
if path.include?("controllers/api")
|
|
11
|
-
path.split(/\/app\/controllers\/api\/v\d+\//).last.split("_endpoint.").first
|
|
12
|
-
elsif path.include?("app/controllers/concerns/api")
|
|
13
|
-
path.split(/\/app\/controllers\/concerns\/api\/v\d+\//).last.split("/endpoint_base.").first
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def self.serializer
|
|
18
|
-
# TODO This could be smart enough to figure out if `V1` is accurate, as well.
|
|
19
|
-
"Api::V1::#{Api.topic.classify}Serializer"
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def self.status(code)
|
|
23
|
-
I18n.t("api.statuses.#{code}")
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def self.title(path)
|
|
27
|
-
I18n.t("#{topic}.api.#{path}")
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def self.heading(path)
|
|
31
|
-
I18n.t("#{topic}.api.fields.#{path}.heading")
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def self.show_desc
|
|
35
|
-
proc do
|
|
36
|
-
success code: 200, model: Api.serializer, message: Api.status(200)
|
|
37
|
-
failure [
|
|
38
|
-
{code: 401, message: Api.status(401)}, # unauthorized
|
|
39
|
-
{code: 403, message: Api.status(403)}, # forbidden
|
|
40
|
-
{code: 404, message: Api.status(404)}, # not found
|
|
41
|
-
{code: 429, message: Api.status(429)} # too many requests
|
|
42
|
-
]
|
|
43
|
-
produces ["application/vnd.api+json"]
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def self.index_desc
|
|
48
|
-
proc do
|
|
49
|
-
success code: 200, model: Api.serializer, message: Api.status(200)
|
|
50
|
-
failure [
|
|
51
|
-
{code: 401, message: Api.status(401)}, # unauthorized
|
|
52
|
-
{code: 429, message: Api.status(429)} # too many requests
|
|
53
|
-
]
|
|
54
|
-
produces ["application/vnd.api+json"]
|
|
55
|
-
is_array true
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def self.create_desc
|
|
60
|
-
proc do
|
|
61
|
-
success code: 201, model: Api.serializer, message: Api.status(201)
|
|
62
|
-
failure [
|
|
63
|
-
{code: 400, message: Api.status(400)}, # bad request
|
|
64
|
-
{code: 401, message: Api.status(401)}, # unauthorized
|
|
65
|
-
{code: 403, message: Api.status(403)}, # forbidden
|
|
66
|
-
{code: 406, message: Api.status(406)}, # not acceptable
|
|
67
|
-
{code: 422, message: Api.status(422)}, # unprocessable entity
|
|
68
|
-
{code: 429, message: Api.status(429)} # too many requests
|
|
69
|
-
]
|
|
70
|
-
consumes ["application/json", "multipart/form-data"]
|
|
71
|
-
produces ["application/vnd.api+json"]
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def self.update_desc
|
|
76
|
-
proc do
|
|
77
|
-
success code: 200, model: Api.serializer, message: Api.status(200)
|
|
78
|
-
failure [
|
|
79
|
-
{code: 400, message: Api.status(400)}, # bad request
|
|
80
|
-
{code: 401, message: Api.status(401)}, # unauthorized
|
|
81
|
-
{code: 403, message: Api.status(403)}, # forbidden
|
|
82
|
-
{code: 404, message: Api.status(404)}, # not found
|
|
83
|
-
{code: 406, message: Api.status(406)}, # not acceptable
|
|
84
|
-
{code: 422, message: Api.status(422)}, # unprocessable entity
|
|
85
|
-
{code: 429, message: Api.status(429)} # too many requests
|
|
86
|
-
]
|
|
87
|
-
consumes ["application/json", "multipart/form-data"]
|
|
88
|
-
produces ["application/vnd.api+json"]
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def self.destroy_desc
|
|
93
|
-
# TODO We don't have anything for this, but we want to make sure it's easy to roll out updates going forward.
|
|
94
|
-
proc {}
|
|
95
|
-
end
|
|
96
|
-
end
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
module Api::V1::Base
|
|
2
|
-
extend ActiveSupport::Concern
|
|
3
|
-
|
|
4
|
-
included do
|
|
5
|
-
include Api::V1::Defaults
|
|
6
|
-
include Api::V1::LoadsAndAuthorizesApiResource
|
|
7
|
-
include Api::V1::ExceptionsHandler
|
|
8
|
-
|
|
9
|
-
version "v1"
|
|
10
|
-
|
|
11
|
-
use ::WineBouncer::OAuth2, message: "Doorkeeper OAuth2 Authentication"
|
|
12
|
-
|
|
13
|
-
rescue_from :all do |error|
|
|
14
|
-
handle_api_error(error)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
BulletTrain::Api.endpoints.each do |endpoint_class|
|
|
18
|
-
mount endpoint_class.constantize
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
after_validation do
|
|
22
|
-
# Ensure responses never get cached.
|
|
23
|
-
header "Cache-Control", "no-store"
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
class_methods do
|
|
28
|
-
# TODO I actually don't know of any way to make this work. This was supposed to be run after all other endpoints
|
|
29
|
-
# are registered, but I don't know of a way to know when we're done running `initializer` blocks from the engines
|
|
30
|
-
# a user may have included.
|
|
31
|
-
def handle_not_found
|
|
32
|
-
route :any, "*path" do
|
|
33
|
-
raise StandardError, "Unable to find API endpoint"
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
module Api::V1::Teams::EndpointBase
|
|
2
|
-
extend ActiveSupport::Concern
|
|
3
|
-
|
|
4
|
-
included do
|
|
5
|
-
helpers do
|
|
6
|
-
params :id do
|
|
7
|
-
requires :id, type: Integer, allow_blank: false, desc: Api.heading(:id)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
params :team do
|
|
11
|
-
optional :name, type: String, allow_blank: false, desc: Api.heading(:name)
|
|
12
|
-
optional :locale, type: String, desc: Api.heading(:locale)
|
|
13
|
-
|
|
14
|
-
# TODO I don't like this, but I can't figure out a better way to accomplish the same thing. I'm open to any
|
|
15
|
-
# suggestions on this. I don't know why `@api.class` returns `Class` but `@api.to_s` returns e.g.
|
|
16
|
-
# `Api::V1::TeamsEndpoint`, but since we can get the latter, we'll use that to fetch whatever proc is defined
|
|
17
|
-
# in ADDITIONAL_PARAMS.
|
|
18
|
-
if defined?(@api.to_s.constantize::PARAMS)
|
|
19
|
-
instance_eval(&@api.to_s.constantize::PARAMS)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
resource :teams, desc: Api.title(:actions) do
|
|
25
|
-
after_validation do
|
|
26
|
-
load_and_authorize_api_resource Team
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
desc Api.title(:index), &Api.index_desc
|
|
30
|
-
oauth2
|
|
31
|
-
paginate per_page: 100
|
|
32
|
-
get "/" do
|
|
33
|
-
@paginated_teams = paginate @teams
|
|
34
|
-
render @paginated_teams, serializer: Api.serializer, adapter: :attributes
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
desc Api.title(:show), &Api.show_desc
|
|
38
|
-
params do
|
|
39
|
-
use :id
|
|
40
|
-
end
|
|
41
|
-
oauth2
|
|
42
|
-
route_param :id do
|
|
43
|
-
get do
|
|
44
|
-
render @team, serializer: Api.serializer
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
desc Api.title(:create), &Api.create_desc
|
|
49
|
-
params do
|
|
50
|
-
use :team
|
|
51
|
-
end
|
|
52
|
-
route_setting :api_resource_options, permission: :create
|
|
53
|
-
oauth2 "write"
|
|
54
|
-
post "/" do
|
|
55
|
-
if @team.save
|
|
56
|
-
# sets the team creator as the default admin
|
|
57
|
-
@team.memberships.create(user: current_user, roles: [Role.admin])
|
|
58
|
-
|
|
59
|
-
current_user.current_team = @team
|
|
60
|
-
current_user.former_user = false
|
|
61
|
-
current_user.save
|
|
62
|
-
|
|
63
|
-
render @team, serializer: Api.serializer
|
|
64
|
-
else
|
|
65
|
-
record_not_saved @team
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
desc Api.title(:update), &Api.update_desc
|
|
70
|
-
params do
|
|
71
|
-
use :id
|
|
72
|
-
use :team
|
|
73
|
-
end
|
|
74
|
-
route_setting :api_resource_options, permission: :update
|
|
75
|
-
oauth2 "write"
|
|
76
|
-
route_param :id do
|
|
77
|
-
put do
|
|
78
|
-
if @team.update(declared(params, include_missing: false))
|
|
79
|
-
render @team, serializer: Api.serializer
|
|
80
|
-
else
|
|
81
|
-
record_not_saved @team
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
class Api::V1::InvitationSerializer < Api::V1::ApplicationSerializer
|
|
2
|
-
include Api::V1::Invitations::SerializerBase
|
|
3
|
-
|
|
4
|
-
# The `:id` entries are redundant, but for the moment they help us generate valid code.
|
|
5
|
-
attributes :id,
|
|
6
|
-
# 🚅 super scaffolding will insert new fields above this line.
|
|
7
|
-
:id
|
|
8
|
-
end
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
# TODO This serializer only needs to exist because of a limitation in `Api.show_desc` that we use in
|
|
2
|
-
# `app/controllers/api/v1/me_endpoint.rb`. This is the easiest solution at the moment, but we can revisit later.
|
|
3
|
-
class Api::V1::MeSerializer < Api::V1::UserSerializer
|
|
4
|
-
end
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
class Api::V1::MembershipSerializer < Api::V1::ApplicationSerializer
|
|
2
|
-
include Api::V1::Memberships::SerializerBase
|
|
3
|
-
|
|
4
|
-
# The `:id` entries are redundant, but for the moment they help us generate valid code.
|
|
5
|
-
attributes :id,
|
|
6
|
-
# 🚅 super scaffolding will insert new fields above this line.
|
|
7
|
-
:id
|
|
8
|
-
end
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
class Api::V1::TeamSerializer < Api::V1::ApplicationSerializer
|
|
2
|
-
include Api::V1::Teams::SerializerBase
|
|
3
|
-
|
|
4
|
-
# The `:id` entries are redundant, but for the moment they help us generate valid code.
|
|
5
|
-
attributes :id,
|
|
6
|
-
# 🚅 super scaffolding will insert new fields above this line.
|
|
7
|
-
:id
|
|
8
|
-
end
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
class Api::V1::UserSerializer < Api::V1::ApplicationSerializer
|
|
2
|
-
include Api::V1::Users::SerializerBase
|
|
3
|
-
|
|
4
|
-
# The `:id` entries are redundant, but for the moment they help us generate valid code.
|
|
5
|
-
attributes :id,
|
|
6
|
-
# 🚅 super scaffolding will insert new fields above this line.
|
|
7
|
-
:id
|
|
8
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
module Api::V1::Invitations::SerializerBase
|
|
2
|
-
extend ActiveSupport::Concern
|
|
3
|
-
|
|
4
|
-
included do
|
|
5
|
-
set_type "invitation"
|
|
6
|
-
|
|
7
|
-
attributes :id,
|
|
8
|
-
:team_id,
|
|
9
|
-
:email,
|
|
10
|
-
:from_membership_id,
|
|
11
|
-
:created_at,
|
|
12
|
-
:updated_at
|
|
13
|
-
|
|
14
|
-
belongs_to :from_membership, serializer: Api::V1::MembershipSerializer
|
|
15
|
-
has_one :membership, serializer: Api::V1::MembershipSerializer
|
|
16
|
-
end
|
|
17
|
-
end
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
module Api::V1::Memberships::SerializerBase
|
|
2
|
-
extend ActiveSupport::Concern
|
|
3
|
-
|
|
4
|
-
included do
|
|
5
|
-
set_type "membership"
|
|
6
|
-
|
|
7
|
-
attributes :id,
|
|
8
|
-
:team_id,
|
|
9
|
-
:user_id,
|
|
10
|
-
:invitation_id,
|
|
11
|
-
:user_first_name,
|
|
12
|
-
:user_last_name,
|
|
13
|
-
:user_profile_photo_id,
|
|
14
|
-
:user_email,
|
|
15
|
-
:added_by_id,
|
|
16
|
-
:created_at,
|
|
17
|
-
:updated_at
|
|
18
|
-
|
|
19
|
-
belongs_to :user, serializer: Api::V1::UserSerializer
|
|
20
|
-
belongs_to :team, serializer: Api::V1::TeamSerializer
|
|
21
|
-
belongs_to :invitation, serializer: Api::V1::InvitationSerializer
|
|
22
|
-
belongs_to :added_by, serializer: Api::V1::MembershipSerializer
|
|
23
|
-
end
|
|
24
|
-
end
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
module Api::V1::Teams::SerializerBase
|
|
2
|
-
extend ActiveSupport::Concern
|
|
3
|
-
|
|
4
|
-
included do
|
|
5
|
-
set_type "team"
|
|
6
|
-
|
|
7
|
-
attributes :id,
|
|
8
|
-
:name,
|
|
9
|
-
:time_zone,
|
|
10
|
-
:locale,
|
|
11
|
-
:created_at,
|
|
12
|
-
:updated_at
|
|
13
|
-
|
|
14
|
-
has_many :scaffolding_absolutely_abstract_creative_concepts, serializer: Api::V1::Scaffolding::AbsolutelyAbstract::CreativeConceptSerializer
|
|
15
|
-
end
|
|
16
|
-
end
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
module Api::V1::Users::SerializerBase
|
|
2
|
-
extend ActiveSupport::Concern
|
|
3
|
-
|
|
4
|
-
included do
|
|
5
|
-
set_type "user"
|
|
6
|
-
|
|
7
|
-
attributes :id,
|
|
8
|
-
:email,
|
|
9
|
-
:first_name,
|
|
10
|
-
:last_name,
|
|
11
|
-
:time_zone,
|
|
12
|
-
:profile_photo_id,
|
|
13
|
-
:former_user,
|
|
14
|
-
:locale,
|
|
15
|
-
:platform_agent_of_id,
|
|
16
|
-
:created_at,
|
|
17
|
-
:updated_at
|
|
18
|
-
|
|
19
|
-
has_many :teams, serializer: Api::V1::TeamSerializer
|
|
20
|
-
has_many :memberships, serializer: Api::V1::MembershipSerializer
|
|
21
|
-
end
|
|
22
|
-
end
|