forest_liana 1.0.11 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c5d035cfb474940bbfffb21f321501251e7d962f
4
- data.tar.gz: ec0f80d79c04bd6b84b2529d0c9f97705629eb1d
3
+ metadata.gz: 051a5e7bf351ed5dd2d28b37ea29b5192ad9c582
4
+ data.tar.gz: 651bdcb3580a39e12c11c2eee7972689ae63270e
5
5
  SHA512:
6
- metadata.gz: 24686c944349dc7a10fe161ceaf84c3796284f9637640d63967eb95e66fc23e959f4ab8be65209bbc4ae95df8d50e91f862fbe2f4c6a912caefd465e1facd931
7
- data.tar.gz: 8fb436268fb827b14cc6da78a93488e8763f91b1e83e6824f07f7440ee824a671b3901c7e0fcc469d9be4c0e8126e8132041cf865666a586ca624fd165f9f3fd
6
+ metadata.gz: d5dedba47b186325219c94bf60a097deeb3ba67636a95149ed95a348b51252a29642b180a7c4932309934c32a9c4ccf689784a73256e766e61d9a7a640190a60
7
+ data.tar.gz: 4c4744360e8503260df8c1d63bb43b456b89ef9841e97c6535dae58b496e217e268c04bb960df35dec3f9758e5b72f176da50788417d6e9952d58bf0a158dc80
@@ -27,8 +27,12 @@ module ForestLiana
27
27
  end
28
28
 
29
29
  def authenticate_user_from_jwt
30
- JWT.decode request.headers['Authorization'].split[1],
31
- ForestLiana.jwt_signing_key
30
+ if request.headers['Authorization']
31
+ JWT.decode request.headers['Authorization'].split[1],
32
+ ForestLiana.jwt_signing_key
33
+ else
34
+ render nothing: true, status: 401
35
+ end
32
36
  end
33
37
 
34
38
  end
@@ -0,0 +1,51 @@
1
+ module ForestLiana
2
+ class AssociationsController < ForestLiana::ApplicationController
3
+
4
+ before_filter :find_resource
5
+ before_filter :find_association
6
+
7
+ def index
8
+ getter = HasManyGetter.new(@resource, @association, params)
9
+ getter.perform
10
+
11
+ render json: serialize_models(getter.records,
12
+ include: includes,
13
+ count: getter.count,
14
+ params: params)
15
+ end
16
+
17
+ private
18
+
19
+ def find_resource
20
+ @resource = SchemaUtils.find_model_from_table_name(params[:collection])
21
+
22
+ if @resource.nil? || !@resource.ancestors.include?(ActiveRecord::Base)
23
+ render json: {status: 404}, status: :not_found
24
+ end
25
+ end
26
+
27
+ def find_association
28
+ @association = @resource.reflect_on_association(
29
+ params[:association_name])
30
+
31
+ if @association.nil?
32
+ render json: {status: 404}, status: :not_found
33
+ end
34
+ end
35
+
36
+ def resource_params
37
+ ResourceDeserializer.new(@resource, params[:resource]).perform
38
+ end
39
+
40
+ def includes
41
+ @association.klass
42
+ .reflect_on_all_associations
43
+ .select do |a|
44
+ [:belongs_to, :has_and_belongs_to_many].include?(a.macro) &&
45
+ !a.options[:polymorphic]
46
+ end
47
+ .map {|a| a.name.to_s }
48
+ end
49
+
50
+ end
51
+ end
@@ -64,7 +64,10 @@ module ForestLiana
64
64
  def includes
65
65
  @resource
66
66
  .reflect_on_all_associations
67
- .select {|a| a.macro == :belongs_to && !a.options[:polymorphic] }
67
+ .select do |a|
68
+ [:belongs_to, :has_and_belongs_to_many].include?(a.macro) &&
69
+ !a.options[:polymorphic]
70
+ end
68
71
  .map {|a| a.name.to_s }
69
72
  end
70
73
 
@@ -36,7 +36,7 @@ module ForestLiana
36
36
  include JSONAPI::Serializer
37
37
 
38
38
  def self_link
39
- "/forest#{super}"
39
+ "/forest#{super.underscore}"
40
40
  end
41
41
 
42
42
  def type
@@ -56,12 +56,16 @@ module ForestLiana
56
56
  end
57
57
 
58
58
  def relationship_related_link(attribute_name)
59
+ ret = {
60
+ href: "#{self_link}/#{format_name(attribute_name)}"
61
+ }
62
+
59
63
  relationship_records = object.send(attribute_name)
60
- return nil unless relationship_records.respond_to?(:each)
64
+ if relationship_records.respond_to?(:each)
65
+ ret[:meta] = { count: relationship_records.count }
66
+ end
61
67
 
62
- {
63
- meta: { count: relationship_records.count }
64
- }
68
+ ret
65
69
  end
66
70
  }
67
71
 
@@ -0,0 +1,51 @@
1
+ module ForestLiana
2
+ class HasManyGetter
3
+ def initialize(resource, association, params)
4
+ @resource = resource
5
+ @association = association
6
+ @params = params
7
+ end
8
+
9
+ def perform
10
+ @records = @resource.find(@params[:id]).send(@params[:association_name])
11
+
12
+ @records
13
+ end
14
+
15
+ def records
16
+ @records.limit(limit).offset(offset)
17
+ end
18
+
19
+ def count
20
+ @records.to_a.length
21
+ end
22
+
23
+ private
24
+
25
+ def offset
26
+ return 0 unless pagination?
27
+
28
+ number = @params[:page][:number]
29
+ if number && number.to_i > 0
30
+ (number.to_i - 1) * limit
31
+ else
32
+ 0
33
+ end
34
+ end
35
+
36
+ def limit
37
+ return 10 unless pagination?
38
+
39
+ if @params[:page][:size]
40
+ @params[:page][:size].to_i
41
+ else
42
+ 10
43
+ end
44
+ end
45
+
46
+ def pagination?
47
+ @params[:page] && @params[:page][:number]
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,27 @@
1
+ module ForestLiana
2
+ class OperatorValueParser
3
+
4
+ def self.parse(value)
5
+ operator = nil
6
+
7
+ if value.first == '!'
8
+ operator = '!='
9
+ value.slice!(0)
10
+ elsif value.first == '>'
11
+ operator = '>'
12
+ value.slice!(0)
13
+ elsif value.first == '<'
14
+ operator = '<'
15
+ value.slice!(0)
16
+ elsif value.include?('*')
17
+ operator = 'ILIKE'
18
+ value.gsub!('*', '%')
19
+ else
20
+ operator = '='
21
+ end
22
+
23
+ [operator, value]
24
+ end
25
+
26
+ end
27
+ end
@@ -6,8 +6,10 @@ module ForestLiana
6
6
  end
7
7
 
8
8
  def perform
9
- @records_without_sort = @records = search_query
9
+ @records = search_query
10
10
  @records = sort_query
11
+
12
+ @records
11
13
  end
12
14
 
13
15
  def records
@@ -15,13 +17,13 @@ module ForestLiana
15
17
  end
16
18
 
17
19
  def count
18
- @records_without_sort.count
20
+ @records.to_a.count
19
21
  end
20
22
 
21
23
  private
22
24
 
23
25
  def search_query
24
- SearchQueryBuilder.new(@resource.includes(includes), @params).perform
26
+ SearchQueryBuilder.new(@resource, @params).perform
25
27
  end
26
28
 
27
29
  def sort_query
@@ -32,7 +34,8 @@ module ForestLiana
32
34
  field = detect_reference(field)
33
35
 
34
36
  association = @resource.reflect_on_association(field.to_sym)
35
- if [:has_many, :has_and_belongs_to_many].include?(association.try(:macro))
37
+ if [:has_many, :has_and_belongs_to_many].include?(
38
+ association.try(:macro))
36
39
  @records = has_many_sort(association, order)
37
40
  else
38
41
  @records = @records.order("#{field} #{order.upcase}")
@@ -52,11 +55,12 @@ module ForestLiana
52
55
  def has_many_sort(association, order)
53
56
  @records
54
57
  .select("#{@resource.table_name}.*,
55
- COUNT(#{association.table_name}.id) has_many_count")
58
+ COUNT(#{association.table_name}.id)
59
+ #{association.table_name}_has_many_count")
56
60
  .joins(ArelHelpers.join_association(@resource, association.name,
57
61
  Arel::Nodes::OuterJoin))
58
62
  .group("#{@resource.table_name}.id")
59
- .order("has_many_count #{order.upcase}")
63
+ .order("#{association.table_name}_has_many_count #{order.upcase}")
60
64
  end
61
65
 
62
66
  def detect_sort_order(field)
@@ -81,8 +85,7 @@ module ForestLiana
81
85
  end
82
86
 
83
87
  def includes
84
- SchemaUtils.associations(@resource).select {|x| !x.options[:through]}
85
- .map(&:name)
88
+ SchemaUtils.associations(@resource).map(&:name)
86
89
  end
87
90
 
88
91
  def offset
@@ -2,16 +2,16 @@ module ForestLiana
2
2
  class SearchQueryBuilder
3
3
 
4
4
  def initialize(resource, params)
5
- @resource = resource
5
+ @resource = @records = resource
6
6
  @params = params
7
7
  end
8
8
 
9
9
  def perform
10
- search_param
11
- filter_param
12
- associations_param
10
+ @records = search_param
11
+ @records = filter_param
12
+ @records = has_many_filter
13
13
 
14
- @resource
14
+ @records
15
15
  end
16
16
 
17
17
  def search_param
@@ -28,49 +28,85 @@ module ForestLiana
28
28
  end
29
29
  end
30
30
 
31
- @resource = @resource.where(conditions.join(' OR '))
31
+ @records = @resource.where(conditions.join(' OR '))
32
32
  end
33
+
34
+ @records
33
35
  end
34
36
 
35
37
  def filter_param
36
38
  if @params[:filter]
37
39
  @params[:filter].each do |field, value|
40
+ next if association?(field)
38
41
 
39
- operator = nil
40
- if value.first == '!'
41
- operator = '!='
42
- value.slice!(0)
43
- elsif value.first == '>'
44
- operator = '>'
45
- value.slice!(0)
46
- elsif value.first == '<'
47
- operator = '<'
48
- value.slice!(0)
49
- elsif value.include?('*')
50
- operator = 'ILIKE'
51
- value.gsub!('*', '%')
52
- else
53
- operator = '='
54
- end
55
-
56
- @resource = @resource.where("#{field} #{operator} '#{value}'")
42
+ operator, value = OperatorValueParser.parse(value)
43
+ @records = @resource.where("#{field} #{operator} '#{value}'")
57
44
  end
58
45
  end
46
+
47
+ @records
48
+ end
49
+
50
+ def association?(field)
51
+ field = field.split(':').first if field.include?(':')
52
+ @resource.reflect_on_association(field.to_sym).present?
59
53
  end
60
54
 
61
- def associations_param
62
- associations = @resource.reflect_on_all_associations(:belongs_to)
55
+ def has_many_association?(field)
56
+ field = field.split(':').first if field.include?(':')
57
+ association = @resource.reflect_on_association(field.to_sym)
58
+
59
+ association.try(:macro) === :has_many
60
+ end
63
61
 
64
- associations.each do |association|
65
- name = association.name.to_s
62
+ def has_many_filter
63
+ if @params[:filter]
64
+ @params[:filter].each do |field, value|
65
+ next unless has_many_association?(field)
66
66
 
67
- if @params[name + 'Id']
68
- @resource = @resource.where("#{name.foreign_key} =
69
- #{@params[name + 'Id']}")
67
+ if field.include?(':')
68
+ @records = has_many_subfield_filter(field, value)
69
+ else
70
+ @records = has_many_field_filter(field, value)
71
+ end
70
72
  end
71
73
  end
74
+
75
+ @records
76
+ end
77
+
78
+ def has_many_field_filter(field, value)
79
+ association = @resource.reflect_on_association(field.to_sym)
80
+ return if association.blank?
81
+
82
+ operator, value = OperatorValueParser.parse(value)
83
+
84
+ @records = @records
85
+ .select("#{@resource.table_name}.*,
86
+ COUNT(#{association.table_name}.id)
87
+ #{association.table_name}_has_many_count")
88
+ .joins(ArelHelpers.join_association(@resource, association.name,
89
+ Arel::Nodes::OuterJoin))
90
+ .group("#{@resource.table_name}.id")
91
+ .having("COUNT(#{association.table_name}) #{operator} #{value}")
72
92
  end
73
93
 
94
+ def has_many_subfield_filter(field, value)
95
+ field, subfield = field.split(':')
96
+
97
+ association = @resource.reflect_on_association(field.to_sym)
98
+ return if association.blank?
99
+
100
+ operator, value = OperatorValueParser.parse(value)
101
+
102
+ @records = @records
103
+ .select("#{@resource.table_name}.*,
104
+ COUNT(#{association.table_name}.id)
105
+ #{association.table_name}_has_many_count")
106
+ .joins(ArelHelpers.join_association(@resource, association.name,
107
+ Arel::Nodes::OuterJoin))
108
+ .group("#{@resource.table_name}.id, #{association.table_name}.#{subfield}")
109
+ .having("#{association.table_name}.#{subfield} #{operator} '#{value}'")
110
+ end
74
111
  end
75
112
  end
76
-
@@ -19,7 +19,11 @@ module ForestLiana
19
19
  resource = @reference_model.find(reference_model_id)
20
20
  customer = resource[@reference_field]
21
21
 
22
- fetch_cards(customer, params)
22
+ if customer.blank?
23
+ @records = []
24
+ else
25
+ fetch_cards(customer, params)
26
+ end
23
27
  end
24
28
 
25
29
  def fetch_cards(customer, params)
@@ -27,8 +27,9 @@ module ForestLiana
27
27
  d.date = Time.at(d.date).to_datetime
28
28
  d.period_start = Time.at(d.period_start).to_datetime
29
29
  d.period_end = Time.at(d.period_end).to_datetime
30
- d.subtotal /= 100
31
- d.total /= 100
30
+ d.subtotal /= 100.00
31
+ d.total /= 100.00
32
+ d.amount_due /= 100.00
32
33
 
33
34
  query = {}
34
35
  query[@reference_field] = d.customer
@@ -27,7 +27,7 @@ module ForestLiana
27
27
 
28
28
  @records = @charges.data.map do |d|
29
29
  d.created = Time.at(d.created).to_datetime
30
- d.amount /= 100
30
+ d.amount /= 100.00
31
31
 
32
32
  query = {}
33
33
  query[@reference_field] = d.customer
data/config/routes.rb CHANGED
@@ -1,14 +1,18 @@
1
1
  ForestLiana::Engine.routes.draw do
2
+ # Stripe Integration
2
3
  get 'stripe_payments' => 'stripe#payments'
3
4
  post 'stripe_payments/refunds' => 'stripe#refund'
4
5
  get 'stripe_cards' => 'stripe#cards'
5
6
  get 'stripe_invoices' => 'stripe#invoices'
6
7
 
8
+ # CRUD
7
9
  get '/' => 'apimaps#index'
8
10
  get ':collection' => 'resources#index'
9
11
  get ':collection/:id' => 'resources#show'
10
- get ':collection/:id' => 'resources#show'
11
12
  post ':collection' => 'resources#create'
12
13
  put ':collection/:id' => 'resources#update'
13
14
  delete ':collection/:id' => 'resources#destroy'
15
+
16
+ # Associations
17
+ get ':collection/:id/:association_name' => 'associations#index'
14
18
  end
@@ -1,3 +1,3 @@
1
1
  module ForestLiana
2
- VERSION = "1.0.11"
2
+ VERSION = "1.1.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forest_liana
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.11
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sandro Munda
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-13 00:00:00.000000000 Z
11
+ date: 2015-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -109,6 +109,7 @@ files:
109
109
  - app/assets/stylesheets/scaffold.css
110
110
  - app/controllers/forest_liana/apimaps_controller.rb
111
111
  - app/controllers/forest_liana/application_controller.rb
112
+ - app/controllers/forest_liana/associations_controller.rb
112
113
  - app/controllers/forest_liana/resources_controller.rb
113
114
  - app/controllers/forest_liana/stripe_controller.rb
114
115
  - app/deserializers/forest_liana/resource_deserializer.rb
@@ -119,6 +120,8 @@ files:
119
120
  - app/serializers/forest_liana/stripe_card_serializer.rb
120
121
  - app/serializers/forest_liana/stripe_invoice_serializer.rb
121
122
  - app/serializers/forest_liana/stripe_payment_serializer.rb
123
+ - app/services/forest_liana/has_many_getter.rb
124
+ - app/services/forest_liana/operator_value_parser.rb
122
125
  - app/services/forest_liana/resource_getter.rb
123
126
  - app/services/forest_liana/resources_getter.rb
124
127
  - app/services/forest_liana/schema_adapter.rb