bullet_train-api 1.0.17 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.bt-link +0 -0
- data/app/controllers/concerns/api/controllers/base.rb +69 -0
- data/app/controllers/concerns/api/v1/teams/controller_base.rb +49 -0
- data/app/controllers/concerns/api/v1/users/controller_base.rb +42 -0
- data/app/views/api/v1/teams/index.json.jbuilder +5 -0
- data/app/views/api/v1/teams/show.json.jbuilder +1 -0
- data/app/views/api/v1/users/index.json.jbuilder +5 -0
- data/app/views/api/v1/users/show.json.jbuilder +1 -0
- data/config/routes.rb +15 -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 +13 -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: ed3abce72a79c24aa195ac79c561df5a1107a6f9037030c9ed2933d7f253ff70
|
4
|
+
data.tar.gz: 6ccd878b5cbe0ca6ffc01d635647ce698fa0e7c93e5672beb7dfeb9cb73b4a77
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e70897a691ad9da425bfcf7f5b065d3611c0b427ed8caaef2c298bf0f045b59548be8e88183d38d932091e088882ea5ecc3240925ec5148e6a7d676fdad78fe3
|
7
|
+
data.tar.gz: 9463944b7a19c08b6e1f62db0b896e938c8715444c5defe4086359dfcfef0562735b3e0d4a5bc375c7555a85e792eafd52b63d5c2d5927213d686e2c97b19c61
|
data/.bt-link
ADDED
File without changes
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require "pagy_cursor/pagy/extras/cursor"
|
2
|
+
require "pagy_cursor/pagy/extras/uuid_cursor"
|
3
|
+
|
4
|
+
module Api::Controllers::Base
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
# TODO Why doesn't `before_action :doorkeeper_authorize!` throw an exception?
|
8
|
+
class NotAuthenticatedError < StandardError
|
9
|
+
end
|
10
|
+
|
11
|
+
included do
|
12
|
+
include ActionController::Helpers
|
13
|
+
helper ApplicationHelper
|
14
|
+
|
15
|
+
include LoadsAndAuthorizesResource
|
16
|
+
include Pagy::Backend
|
17
|
+
|
18
|
+
before_action :set_default_response_format
|
19
|
+
before_action :doorkeeper_authorize!
|
20
|
+
|
21
|
+
rescue_from CanCan::AccessDenied, ActiveRecord::RecordNotFound do |exception|
|
22
|
+
render json: {error: "Not found"}, status: :not_found
|
23
|
+
end
|
24
|
+
|
25
|
+
rescue_from NotAuthenticatedError do |exception|
|
26
|
+
render json: {error: "Invalid token"}, status: :unauthorized
|
27
|
+
end
|
28
|
+
|
29
|
+
before_action :apply_pagination, only: [:index]
|
30
|
+
end
|
31
|
+
|
32
|
+
def permitted_fields
|
33
|
+
[]
|
34
|
+
end
|
35
|
+
|
36
|
+
def permitted_arrays
|
37
|
+
{}
|
38
|
+
end
|
39
|
+
|
40
|
+
def process_params(strong_params)
|
41
|
+
end
|
42
|
+
|
43
|
+
def current_user
|
44
|
+
raise NotAuthenticatedError unless doorkeeper_token.present?
|
45
|
+
@current_user ||= User.find_by(id: doorkeeper_token[:resource_owner_id])
|
46
|
+
end
|
47
|
+
|
48
|
+
def current_team
|
49
|
+
# Application agents are users but only have one team.
|
50
|
+
current_user&.teams&.first
|
51
|
+
end
|
52
|
+
|
53
|
+
def apply_pagination
|
54
|
+
collection_variable = "@#{self.class.name.split("::").last.gsub("Controller", "").underscore}"
|
55
|
+
collection = instance_variable_get collection_variable
|
56
|
+
@pagy, collection = pagy_cursor collection
|
57
|
+
instance_variable_set collection_variable, collection
|
58
|
+
end
|
59
|
+
|
60
|
+
def set_default_response_format
|
61
|
+
request.format = :json
|
62
|
+
end
|
63
|
+
|
64
|
+
class_methods do
|
65
|
+
def regex_to_remove_controller_namespace
|
66
|
+
/^#{name.split("::").first(2).join("::") + "::"}/
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Api::V1::Teams::ControllerBase
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
module StrongParameters
|
5
|
+
# Only allow a list of trusted parameters through.
|
6
|
+
def team_params
|
7
|
+
strong_params = params.require(:team).permit(
|
8
|
+
*permitted_fields,
|
9
|
+
:name,
|
10
|
+
:time_zone,
|
11
|
+
:locale,
|
12
|
+
# 🚅 super scaffolding will insert new fields above this line.
|
13
|
+
*permitted_arrays,
|
14
|
+
# 🚅 super scaffolding will insert new arrays above this line.
|
15
|
+
)
|
16
|
+
|
17
|
+
process_params(strong_params)
|
18
|
+
|
19
|
+
strong_params
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
included do
|
24
|
+
load_and_authorize_resource :team, class: "Team", prepend: true,
|
25
|
+
member_actions: (defined?(MEMBER_ACTIONS) ? MEMBER_ACTIONS : []),
|
26
|
+
collection_actions: (defined?(COLLECTION_ACTIONS) ? COLLECTION_ACTIONS : [])
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
include StrongParameters
|
31
|
+
end
|
32
|
+
|
33
|
+
# GET /api/v1/teams
|
34
|
+
def index
|
35
|
+
end
|
36
|
+
|
37
|
+
# GET /api/v1/teams/:id
|
38
|
+
def show
|
39
|
+
end
|
40
|
+
|
41
|
+
# PATCH/PUT /api/v1/teams/:id
|
42
|
+
def update
|
43
|
+
if @team.update(team_params)
|
44
|
+
render :show
|
45
|
+
else
|
46
|
+
render json: @team.errors, status: :unprocessable_entity
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Api::V1::Users::ControllerBase
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
module StrongParameters
|
5
|
+
# Only allow a list of trusted parameters through.
|
6
|
+
def user_params
|
7
|
+
strong_params = params.require(:user).permit(
|
8
|
+
*permitted_fields,
|
9
|
+
:email,
|
10
|
+
:first_name,
|
11
|
+
:last_name,
|
12
|
+
:time_zone,
|
13
|
+
:locale,
|
14
|
+
# 🚅 super scaffolding will insert new fields above this line.
|
15
|
+
*permitted_arrays,
|
16
|
+
# 🚅 super scaffolding will insert new arrays above this line.
|
17
|
+
)
|
18
|
+
|
19
|
+
process_params(strong_params)
|
20
|
+
|
21
|
+
strong_params
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
included do
|
26
|
+
load_and_authorize_resource :user, class: "User", prepend: true,
|
27
|
+
member_actions: (defined?(MEMBER_ACTIONS) ? MEMBER_ACTIONS : []),
|
28
|
+
collection_actions: (defined?(COLLECTION_ACTIONS) ? COLLECTION_ACTIONS : [])
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
include StrongParameters
|
33
|
+
end
|
34
|
+
|
35
|
+
# GET /api/v1/users
|
36
|
+
def index
|
37
|
+
end
|
38
|
+
|
39
|
+
# GET /api/v1/users/:id
|
40
|
+
def show
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
json.partial! "api/v1/teams/team", team: @team
|
@@ -0,0 +1 @@
|
|
1
|
+
json.partial! "api/v1/users/user", user: @user
|
data/config/routes.rb
CHANGED
@@ -1,4 +1,18 @@
|
|
1
1
|
Rails.application.routes.draw do
|
2
2
|
use_doorkeeper
|
3
|
-
|
3
|
+
|
4
|
+
namespace :api do
|
5
|
+
namespace :v1 do
|
6
|
+
shallow do
|
7
|
+
resources :users
|
8
|
+
resources :teams do
|
9
|
+
resources :invitations
|
10
|
+
resources :memberships
|
11
|
+
namespace :platform do
|
12
|
+
resources :applications
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
4
18
|
end
|
@@ -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.
|
4
|
+
version: 1.1.2
|
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-04 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
|
@@ -199,32 +115,16 @@ executables: []
|
|
199
115
|
extensions: []
|
200
116
|
extra_rdoc_files: []
|
201
117
|
files:
|
118
|
+
- ".bt-link"
|
202
119
|
- MIT-LICENSE
|
203
120
|
- README.md
|
204
121
|
- Rakefile
|
205
122
|
- app/assets/config/bullet_train_api_manifest.js
|
206
123
|
- app/controllers/account/platform/applications_controller.rb
|
207
|
-
- app/controllers/api.rb
|
208
|
-
- app/controllers/api/
|
209
|
-
- app/controllers/api/
|
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
|
124
|
+
- app/controllers/concerns/api/controllers/base.rb
|
125
|
+
- app/controllers/concerns/api/v1/teams/controller_base.rb
|
126
|
+
- app/controllers/concerns/api/v1/users/controller_base.rb
|
218
127
|
- 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
128
|
- app/views/account/platform/applications/_application.json.jbuilder
|
229
129
|
- app/views/account/platform/applications/_breadcrumbs.html.erb
|
230
130
|
- app/views/account/platform/applications/_form.html.erb
|
@@ -236,6 +136,10 @@ files:
|
|
236
136
|
- app/views/account/platform/applications/new.html.erb
|
237
137
|
- app/views/account/platform/applications/show.html.erb
|
238
138
|
- app/views/account/platform/applications/show.json.jbuilder
|
139
|
+
- app/views/api/v1/teams/index.json.jbuilder
|
140
|
+
- app/views/api/v1/teams/show.json.jbuilder
|
141
|
+
- app/views/api/v1/users/index.json.jbuilder
|
142
|
+
- app/views/api/v1/users/show.json.jbuilder
|
239
143
|
- config/locales/en/api.en.yml
|
240
144
|
- config/locales/en/me.en.yml
|
241
145
|
- config/locales/en/platform/applications.en.yml
|
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
|