forest_liana 1.0.11 → 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 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