introspective_grape 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/.travis.yml +16 -3
- data/CHANGELOG.md +16 -8
- data/README.md +6 -6
- data/gemfiles/2.0.0-Gemfile +1 -1
- data/gemfiles/Gemfile.rails.3.2.22 +1 -1
- data/gemfiles/Gemfile.rails.4.1.13 +1 -1
- data/gemfiles/Gemfile.rails.4.2.7.1 +1 -1
- data/gemfiles/Gemfile.rails.4.2.7.1.new.swagger +1 -1
- data/gemfiles/Gemfile.rails.4.2.8 +1 -1
- data/gemfiles/Gemfile.rails.5.0.1 +1 -1
- data/gemfiles/Gemfile.rails.master +1 -1
- data/introspective_grape.gemspec +2 -2
- data/lib/introspective_grape/api.rb +16 -16
- data/lib/introspective_grape/camel_snake.rb +5 -4
- data/lib/introspective_grape/filters.rb +2 -2
- data/lib/introspective_grape/formatter/camel_json.rb +12 -9
- data/lib/introspective_grape/helpers.rb +3 -3
- data/lib/introspective_grape/snake_params.rb +2 -1
- data/lib/introspective_grape/traversal.rb +5 -5
- data/lib/introspective_grape/validators.rb +1 -1
- data/lib/introspective_grape/version.rb +1 -1
- data/spec/dummy/app/api/dummy/chat_api.rb +4 -4
- data/spec/dummy/app/api/dummy/company_api.rb +1 -1
- data/spec/dummy/app/api/dummy/location_api.rb +2 -2
- data/spec/dummy/app/api/dummy/project_api.rb +1 -1
- data/spec/dummy/app/api/dummy/sessions.rb +3 -3
- data/spec/dummy/app/api/dummy/user_api.rb +1 -1
- data/spec/dummy/app/api/dummy_api.rb +0 -3
- data/spec/dummy/app/api/error_handlers.rb +2 -2
- data/spec/dummy/app/models/admin_user.rb +1 -1
- data/spec/dummy/app/models/chat.rb +1 -1
- data/spec/dummy/app/models/chat_message.rb +1 -1
- data/spec/dummy/app/models/chat_user.rb +1 -1
- data/spec/dummy/app/models/company.rb +1 -1
- data/spec/dummy/app/models/image.rb +1 -1
- data/spec/dummy/app/models/project.rb +1 -1
- data/spec/dummy/app/models/user.rb +1 -1
- data/spec/dummy/app/models/user/chatter.rb +4 -4
- data/spec/dummy/app/models/user_location.rb +4 -4
- data/spec/dummy/app/policies/location_policy.rb +1 -1
- data/spec/dummy/app/policies/project_policy.rb +5 -5
- data/spec/dummy/app/policies/role_policy.rb +2 -2
- data/spec/dummy/app/policies/user_policy.rb +1 -1
- data/spec/dummy/db/migrate/20150414213154_add_user_authentication_token.rb +1 -1
- data/spec/dummy/db/migrate/20150601212924_create_location_beacons.rb +1 -1
- data/spec/dummy/db/migrate/20150616205336_add_role_user_constraint.rb +1 -1
- data/spec/dummy/db/migrate/20150727214950_add_confirmable_to_devise.rb +1 -1
- data/spec/dummy/db/migrate/20150820190524_add_user_names.rb +2 -2
- data/spec/models/project_spec.rb +3 -3
- data/spec/models/role_spec.rb +6 -6
- data/spec/models/team_spec.rb +2 -2
- data/spec/models/team_user_spec.rb +4 -4
- data/spec/models/user_location_spec.rb +1 -1
- data/spec/models/user_project_job_spec.rb +2 -2
- data/spec/models/user_spec.rb +10 -10
- data/spec/requests/chat_api_spec.rb +7 -7
- data/spec/requests/company_api_spec.rb +4 -4
- data/spec/requests/location_api_spec.rb +10 -10
- data/spec/requests/project_api_spec.rb +18 -18
- data/spec/requests/role_api_spec.rb +1 -1
- data/spec/requests/sessions_api_spec.rb +3 -3
- data/spec/requests/swagger_spec.rb +1 -1
- data/spec/requests/user_api_spec.rb +13 -13
- data/spec/support/blueprints.rb +10 -10
- data/spec/support/location_helper.rb +6 -6
- data/spec/support/request_helpers.rb +4 -3
- metadata +6 -10
- data/lib/.DS_Store +0 -0
- data/spec/.DS_Store +0 -0
- data/spec/dummy/app/api/.DS_Store +0 -0
@@ -1,11 +1,12 @@
|
|
1
1
|
module IntrospectiveGrape
|
2
2
|
module SnakeParams
|
3
|
+
|
3
4
|
def snake_params_before_validation
|
4
5
|
before_validation do
|
5
6
|
# We have to snake case the Rack params then re-assign @params to the
|
6
7
|
# request.params, because of the I-think-very-goofy-and-inexplicable
|
7
8
|
# way Grape interacts with both independently of each other
|
8
|
-
(
|
9
|
+
(CamelSnakeKeys.snake_keys(params)||{}).each do |k,v|
|
9
10
|
request.delete_param(k.camelize(:lower))
|
10
11
|
request.update_param(k, v)
|
11
12
|
end
|
@@ -9,14 +9,14 @@ module IntrospectiveGrape::Traversal
|
|
9
9
|
# (the traversal of the intermediate nodes occurs in find_leaf())
|
10
10
|
return record if routes.size < 2 # the leaf is the root
|
11
11
|
record = find_leaf(routes, record, params)
|
12
|
-
if record
|
12
|
+
if record
|
13
13
|
assoc = routes.last
|
14
|
-
if assoc.many?
|
14
|
+
if assoc.many?
|
15
15
|
leaves = record.send( assoc.reflection.name ).includes( default_includes(assoc.model) )
|
16
16
|
verify_records_found(leaves, routes)
|
17
17
|
leaves
|
18
|
-
else
|
19
|
-
# has_one associations don't return a CollectionProxy and so don't support
|
18
|
+
else
|
19
|
+
# has_one associations don't return a CollectionProxy and so don't support
|
20
20
|
# eager loading.
|
21
21
|
record.send( assoc.reflection.name )
|
22
22
|
end
|
@@ -24,7 +24,7 @@ module IntrospectiveGrape::Traversal
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def verify_records_found(leaves, routes)
|
27
|
-
unless (leaves.map(&:class) - [routes.last.model]).empty?
|
27
|
+
unless (leaves.map(&:class) - [routes.last.model]).empty?
|
28
28
|
raise ActiveRecord::RecordNotFound.new("Records contain the wrong models, they should all be #{routes.last.model.name}, found #{records.map(&:class).map(&:name).join(',')}")
|
29
29
|
end
|
30
30
|
end
|
@@ -14,7 +14,7 @@ module Grape::Validators
|
|
14
14
|
class JsonArray < Grape::Validations::Base
|
15
15
|
def validate_param!(field, params)
|
16
16
|
begin
|
17
|
-
raise unless JSON.parse( params[field] ).kind_of? Array
|
17
|
+
raise unless JSON.parse( params[field] ).kind_of? Array
|
18
18
|
rescue
|
19
19
|
fail Grape::Exceptions::Validation, params: [@scope.full_name(field)], message: 'must be a valid JSON array!'
|
20
20
|
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
class Dummy::ChatAPI < Grape::API
|
2
2
|
formatter :json, IntrospectiveGrape::Formatter::CamelJson
|
3
3
|
|
4
|
-
before do
|
4
|
+
before do
|
5
5
|
authenticate!
|
6
6
|
end
|
7
7
|
|
8
|
-
resource :chats do
|
8
|
+
resource :chats do
|
9
9
|
|
10
|
-
desc "list the current user's existing chats"
|
10
|
+
desc "list the current user's existing chats"
|
11
11
|
get '/' do
|
12
12
|
authorize Chat.new, :index?
|
13
13
|
present current_user.chats.includes(:users), with: ChatEntity
|
@@ -103,6 +103,6 @@ class Dummy::ChatAPI < Grape::API
|
|
103
103
|
class MessageEntity < Grape::Entity
|
104
104
|
expose :id, :chat_id, :message
|
105
105
|
expose :author, using: UserEntity
|
106
|
-
end
|
106
|
+
end
|
107
107
|
|
108
108
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class Dummy::LocationAPI < IntrospectiveGrape::API
|
2
|
-
exclude_actions Location, :none
|
3
|
-
include_actions LocationBeacon, :index
|
2
|
+
exclude_actions Location, :none
|
3
|
+
include_actions LocationBeacon, :index
|
4
4
|
include_actions LocationGps, :index
|
5
5
|
|
6
6
|
default_includes Location, :child_locations, :gps, :beacons, :locatables
|
@@ -11,7 +11,7 @@ class Dummy::ProjectAPI < IntrospectiveGrape::API
|
|
11
11
|
|
12
12
|
paginate per_page: 2, max_per_page: 10, offset: 2
|
13
13
|
|
14
|
-
restful Project, [:id, teams_attributes: [:id,:name,:_destroy, team_users_attributes: [:id, :user_id, :_destroy] ]]
|
14
|
+
restful Project, [:id, teams_attributes: [:id,:name,:_destroy, team_users_attributes: [:id, :user_id, :_destroy] ]]
|
15
15
|
|
16
16
|
class AdminEntity < Grape::Entity
|
17
17
|
expose :id, as: :user_id
|
@@ -34,18 +34,18 @@ class Dummy::Sessions < Grape::API
|
|
34
34
|
|
35
35
|
|
36
36
|
desc "delete a user session" do
|
37
|
-
detail "sign out the current user"
|
37
|
+
detail "sign out the current user"
|
38
38
|
end
|
39
39
|
delete '/' do
|
40
40
|
authorize User.new, :sessions?
|
41
41
|
u = User.find_by_authentication_token(params[:api_key])
|
42
|
-
if u
|
42
|
+
if u
|
43
43
|
u.authentication_token = nil
|
44
44
|
{status: u.save!}
|
45
45
|
else
|
46
46
|
{status: true } # the user is already logged out
|
47
47
|
end
|
48
|
-
end
|
48
|
+
end
|
49
49
|
|
50
50
|
end
|
51
51
|
end
|
@@ -32,6 +32,6 @@ class Dummy::UserAPI < IntrospectiveGrape::API
|
|
32
32
|
expose :id, :email, :first_name, :last_name, :avatar_url, :created_at
|
33
33
|
expose :roles, as: :roles_attributes, using: RoleEntity
|
34
34
|
expose :user_project_jobs, as: :user_project_jobs_attributes, using: UserProjectJobEntity
|
35
|
-
end
|
35
|
+
end
|
36
36
|
|
37
37
|
end
|
@@ -15,9 +15,6 @@ class DummyAPI < Grape::API
|
|
15
15
|
# sets server date in response header. This can be used on the client side
|
16
16
|
header "X-Server-Date", Time.now.to_i.to_s
|
17
17
|
header "Expires", 1.year.ago.httpdate
|
18
|
-
# Convert incoming camel case params to snake case: grape will totally blow this
|
19
|
-
# if the params hash is not a Hashie::Mash, so make it one of those:
|
20
|
-
#@params = Hashie::Mash.new(params.with_snake_keys)
|
21
18
|
end
|
22
19
|
|
23
20
|
before_validation do
|
@@ -18,11 +18,11 @@ module ErrorHandlers
|
|
18
18
|
end
|
19
19
|
|
20
20
|
m.rescue_from Pundit::NotAuthorizedError do
|
21
|
-
error_response message: "Forbidden", status: 403
|
21
|
+
error_response message: "Forbidden", status: 403
|
22
22
|
end
|
23
23
|
|
24
24
|
m.rescue_from Pundit::NotDefinedError do
|
25
|
-
error_response message: "Policy not implemented", status: 501
|
25
|
+
error_response message: "Policy not implemented", status: 501
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class AdminUser < ActiveRecord::Base
|
2
2
|
# Include default devise modules. Others available are:
|
3
3
|
# :confirmable, :lockable, :timeoutable and :omniauthable
|
4
|
-
devise :database_authenticatable,
|
4
|
+
devise :database_authenticatable,
|
5
5
|
:recoverable, :rememberable, :trackable, :validatable
|
6
6
|
end
|
@@ -10,7 +10,7 @@ class Chat < AbstractAdapter
|
|
10
10
|
chat_users.includes(:user).select {|cu| cu.departed_at.nil? }.map(&:user)
|
11
11
|
end
|
12
12
|
|
13
|
-
before_create :add_creator_to_conversation
|
13
|
+
before_create :add_creator_to_conversation
|
14
14
|
def add_creator_to_conversation
|
15
15
|
users.push creator
|
16
16
|
end
|
@@ -2,7 +2,7 @@ class Company < AbstractAdapter
|
|
2
2
|
has_many :roles, as: :ownable
|
3
3
|
has_many :admins, through: :roles, source: :user
|
4
4
|
accepts_nested_attributes_for :roles, allow_destroy: true
|
5
|
-
|
5
|
+
|
6
6
|
has_many :beacons, class_name: 'LocationBeacon', dependent: :destroy
|
7
7
|
has_many :locatables
|
8
8
|
has_many :locations, through: :locatables, source: :locatable, source_type: 'Company'
|
@@ -5,7 +5,7 @@ class Image < ActiveRecord::Base
|
|
5
5
|
|
6
6
|
has_attached_file :file, styles: {medium: "300x300>", thumb: "100x100"},
|
7
7
|
url: "/system/:imageable_type/:imageable_id/:id/:style/:filename"
|
8
|
-
|
8
|
+
|
9
9
|
validates_attachment :file, content_type: {content_type: ["image/jpeg", "image/png", "image/gif"]}
|
10
10
|
validates_attachment_size :file, :less_than => 2.megabytes
|
11
11
|
|
@@ -8,7 +8,7 @@ class Project < AbstractAdapter
|
|
8
8
|
has_many :project_jobs, dependent: :destroy, inverse_of: :project
|
9
9
|
has_many :jobs, through: :project_jobs
|
10
10
|
accepts_nested_attributes_for :project_jobs, allow_destroy: true
|
11
|
-
|
11
|
+
|
12
12
|
has_many :user_project_jobs, dependent: :destroy, inverse_of: :project
|
13
13
|
has_many :users, through: :user_project_jobs, inverse_of: :projects
|
14
14
|
accepts_nested_attributes_for :user_project_jobs, allow_destroy: true
|
@@ -28,7 +28,7 @@ class User < AbstractAdapter
|
|
28
28
|
has_many :chat_users
|
29
29
|
has_many :chats, through: :chat_users
|
30
30
|
has_many :chat_message_users
|
31
|
-
has_many :messages, ->{ where('chat_messages.created_at >= chat_users.created_at and (chat_users.departed_at IS NULL OR chat_messages.created_at <= chat_users.departed_at)') }, through: :chats
|
31
|
+
has_many :messages, ->{ where('chat_messages.created_at >= chat_users.created_at and (chat_users.departed_at IS NULL OR chat_messages.created_at <= chat_users.departed_at)') }, through: :chats
|
32
32
|
include User::Chatter
|
33
33
|
|
34
34
|
has_many :roles, dependent: :destroy, inverse_of: :user
|
@@ -1,14 +1,14 @@
|
|
1
1
|
module User::Chatter
|
2
2
|
|
3
3
|
def message_query(chat_id, new = true)
|
4
|
-
messages.joins(:chat_message_users)
|
4
|
+
messages.joins(:chat_message_users)
|
5
5
|
.where('chat_message_users.user_id'=> id)
|
6
6
|
.where(new ? {'chat_message_users.read_at'=>nil} : '')
|
7
7
|
.where(chat_id ? {'chat_messages.chat_id'=> chat_id} : '')
|
8
8
|
.order('') # or it will add an order by id clause that breaks the count query.
|
9
9
|
end
|
10
10
|
|
11
|
-
def new_messages?(chat=nil) # returns a hash of chat_ids with new message counts
|
11
|
+
def new_messages?(chat=nil) # returns a hash of chat_ids with new message counts
|
12
12
|
chat_id = chat.kind_of?(Chat) ? chat.id : chat
|
13
13
|
new = message_query(chat_id)
|
14
14
|
.select("chat_messages.chat_id, count(chat_messages.id) as count")
|
@@ -30,7 +30,7 @@ module User::Chatter
|
|
30
30
|
chat = Chat.create(creator: self)
|
31
31
|
chat.users.push users
|
32
32
|
chat.messages.build(message: message, author: self)
|
33
|
-
chat.save!
|
33
|
+
chat.save!
|
34
34
|
chat
|
35
35
|
end
|
36
36
|
|
@@ -51,7 +51,7 @@ module User::Chatter
|
|
51
51
|
chat.users.push users
|
52
52
|
chat.messages.build(chat: chat, author: self, message: "#{self.name} [[ADDED_USER_MESSAGE]] #{users.map(&:name).join(',')}")
|
53
53
|
chat.save!
|
54
|
-
else
|
54
|
+
else
|
55
55
|
chat.errors[:base] << "Only current chat participants can add users."
|
56
56
|
raise ActiveRecord::RecordInvalid.new(chat)
|
57
57
|
end
|
@@ -5,7 +5,7 @@ class UserLocation < AbstractAdapter
|
|
5
5
|
|
6
6
|
validates_inclusion_of :detectable_type, in: %w(LocationBeacon LocationGps)
|
7
7
|
|
8
|
-
default_scope { includes(:detectable).order("created_at desc") }
|
8
|
+
default_scope { includes(:detectable).order("created_at desc") }
|
9
9
|
|
10
10
|
def coords=(c) # convenience method to set coordinates by an array of [lat,lng,alt]
|
11
11
|
self.lat = c[0]
|
@@ -13,14 +13,14 @@ class UserLocation < AbstractAdapter
|
|
13
13
|
self.alt = c[2]
|
14
14
|
end
|
15
15
|
|
16
|
-
def beacon
|
16
|
+
def beacon
|
17
17
|
detectable.is_a?(LocationBeacon) ? detectable : {}
|
18
18
|
end
|
19
19
|
|
20
|
-
def distance
|
20
|
+
def distance
|
21
21
|
if location.gps && lat && lng
|
22
22
|
location.gps.distance_from(lat,lng)
|
23
|
-
else
|
23
|
+
else
|
24
24
|
nil
|
25
25
|
end
|
26
26
|
end
|
@@ -8,23 +8,23 @@ class ProjectPolicy < ApplicationPolicy
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def project_manager?
|
11
|
-
@user.superuser? || @user.all_admin_projects.include?(record)
|
11
|
+
@user.superuser? || @user.all_admin_projects.include?(record)
|
12
12
|
end
|
13
13
|
|
14
14
|
def show?
|
15
|
-
@user && project_user?
|
15
|
+
@user && project_user?
|
16
16
|
end
|
17
17
|
|
18
18
|
def update?
|
19
|
-
@user && project_manager?
|
19
|
+
@user && project_manager?
|
20
20
|
end
|
21
21
|
|
22
22
|
def create?
|
23
|
-
@user && project_manager?
|
23
|
+
@user && project_manager?
|
24
24
|
end
|
25
25
|
|
26
26
|
def destroy?
|
27
|
-
@user && project_manager?
|
27
|
+
@user && project_manager?
|
28
28
|
end
|
29
29
|
|
30
30
|
class Scope < ApplicationPolicy::Scope
|
@@ -5,7 +5,7 @@ class CreateLocationBeacons < ActiveRecord::Migration
|
|
5
5
|
t.references :company, null: false
|
6
6
|
t.string :mac_address, limit: 12
|
7
7
|
t.string :uuid, null: false, limit: 32
|
8
|
-
t.integer :major, null: false
|
8
|
+
t.integer :major, null: false
|
9
9
|
t.integer :minor, null: false
|
10
10
|
|
11
11
|
t.timestamps null: false
|
data/spec/models/project_spec.rb
CHANGED
@@ -2,15 +2,15 @@ require 'rails_helper'
|
|
2
2
|
|
3
3
|
RSpec.describe Project, type: :model do
|
4
4
|
|
5
|
-
it "should make a valid instance" do
|
5
|
+
it "should make a valid instance" do
|
6
6
|
Project.make.valid?.should == true
|
7
7
|
end
|
8
8
|
|
9
|
-
it "should save a valid instance" do
|
9
|
+
it "should save a valid instance" do
|
10
10
|
Project.make!.should == Project.last
|
11
11
|
end
|
12
12
|
|
13
|
-
it "should be owned by a company" do
|
13
|
+
it "should be owned by a company" do
|
14
14
|
Project.make.owner.kind_of?(Company).should == true
|
15
15
|
end
|
16
16
|
|