fera-api 0.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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.idea/fera-api.iml +86 -0
  3. data/.idea/modules.xml +8 -0
  4. data/.idea/vcs.xml +6 -0
  5. data/.idea/workspace.xml +91 -0
  6. data/.rspec +3 -0
  7. data/.rubocop.yml +56 -0
  8. data/Gemfile +14 -0
  9. data/Gemfile.lock +92 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +256 -0
  12. data/Rakefile +12 -0
  13. data/lib/fera/api/version.rb +7 -0
  14. data/lib/fera/api.rb +69 -0
  15. data/lib/fera/app.rb +33 -0
  16. data/lib/fera/models/base.rb +374 -0
  17. data/lib/fera/models/collection.rb +26 -0
  18. data/lib/fera/models/concerns/belongs_to_customer.rb +70 -0
  19. data/lib/fera/models/concerns/belongs_to_order.rb +87 -0
  20. data/lib/fera/models/concerns/belongs_to_product.rb +48 -0
  21. data/lib/fera/models/concerns/belongs_to_review.rb +40 -0
  22. data/lib/fera/models/concerns/belongs_to_submission.rb +39 -0
  23. data/lib/fera/models/concerns/has_many_orders.rb +30 -0
  24. data/lib/fera/models/concerns/has_many_reviews.rb +30 -0
  25. data/lib/fera/models/concerns/has_many_submissions.rb +30 -0
  26. data/lib/fera/models/concerns/has_media.rb +95 -0
  27. data/lib/fera/models/concerns/has_subject.rb +44 -0
  28. data/lib/fera/models/customer.rb +8 -0
  29. data/lib/fera/models/media.rb +55 -0
  30. data/lib/fera/models/order.rb +5 -0
  31. data/lib/fera/models/photo.rb +5 -0
  32. data/lib/fera/models/product.rb +12 -0
  33. data/lib/fera/models/rating.rb +9 -0
  34. data/lib/fera/models/review.rb +18 -0
  35. data/lib/fera/models/store.rb +11 -0
  36. data/lib/fera/models/submission.rb +19 -0
  37. data/lib/fera/models/video.rb +5 -0
  38. data/lib/fera/models/webhook.rb +4 -0
  39. data/lib/fera.rb +4 -0
  40. metadata +167 -0
@@ -0,0 +1,48 @@
1
+ require 'active_support/concern'
2
+
3
+ module Fera
4
+ module BelongsToProduct
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ belongs_to :product, class_name: "Fera::Product"
9
+ end
10
+
11
+ def product=(product)
12
+ product_id = if product.is_a?(Product)
13
+ product.id
14
+ else
15
+ product.try(:with_indifferent_access).try(:[], :id)
16
+ end
17
+ external_product_id = if product.is_a?(Product)
18
+ product.external_id
19
+ else
20
+ product.try(:with_indifferent_access).try(:[], :external_id)
21
+ end
22
+ @product = if product.is_a?(Product)
23
+ product
24
+ else
25
+ Product.new(product, product_id.present?)
26
+ end
27
+ self.attributes['product_id'] = product_id
28
+ self.attributes['external_product_id'] = external_product_id
29
+ self.attributes.delete('product')
30
+ @product
31
+ end
32
+
33
+ def product
34
+ if @product.present?
35
+ @product
36
+ elsif attributes.key?('product') && attributes['product'].present?
37
+ Product.new(attributes['product'], true)
38
+ elsif attributes.key?('product_id') && product_id.present?
39
+ Product.find(product_id)
40
+ elsif attributes.key?('external_product_id') && external_product_id.present?
41
+ Product.find(external_product_id)
42
+ else
43
+ nil
44
+ end
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,40 @@
1
+ require 'active_support/concern'
2
+
3
+ module Fera
4
+ module BelongsToReview
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ belongs_to :review, class_name: "Fera::Review"
9
+ end
10
+
11
+ def review=(review)
12
+ review_id = if review.is_a?(Review)
13
+ review.id
14
+ else
15
+ review.try(:with_indifferent_access).try(:[], :id)
16
+ end
17
+ @review = if review.is_a?(Review)
18
+ review
19
+ else
20
+ Review.new(review, review_id.present?)
21
+ end
22
+ self.attributes['review_id'] = review_id
23
+ self.attributes.delete('review')
24
+ @review
25
+ end
26
+
27
+ def review
28
+ if @review.present?
29
+ @review
30
+ elsif attributes.key?('review') && attributes['review'].present?
31
+ Review.new(attributes['review'], true)
32
+ elsif attributes.key?('review_id') && review_id.present?
33
+ Review.find(review_id)
34
+ else
35
+ nil
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,39 @@
1
+ require 'active_support/concern'
2
+
3
+ module Fera
4
+ module BelongsToSubmission
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ belongs_to :submission, class_name: "Fera::Submission"
9
+ end
10
+
11
+ def submission=(submission)
12
+ submission_id = if submission.is_a?(Submission)
13
+ submission.id
14
+ else
15
+ submission.try(:with_indifferent_access).try(:[], :id)
16
+ end
17
+ @submission = if submission.is_a?(Submission)
18
+ submission
19
+ else
20
+ Submission.new(submission, submission_id.present?)
21
+ end
22
+ self.attributes['submission_id'] = submission_id
23
+ self.attributes.delete('submission')
24
+ @submission
25
+ end
26
+
27
+ def submission
28
+ if @submission.present?
29
+ @submission
30
+ elsif attributes.key?('submission') && attributes['submission'].present?
31
+ Submission.new(attributes['submission'], true)
32
+ elsif attributes.key?('submission_id') && submission_id.present?
33
+ Submission.find(submission_id)
34
+ else
35
+ nil
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,30 @@
1
+ require 'active_support/concern'
2
+
3
+ module Fera
4
+ module HasManyOrders
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ has_many :orders, class_name: "Fera::Order"
9
+ end
10
+
11
+ def orders=(new_orders)
12
+ @orders = new_orders.to_a.map do |model|
13
+ if model.is_a?(Order)
14
+ model
15
+ else
16
+ model_id = model.try(:with_indifferent_access).try(:[], :id)
17
+ Order.new(model, model_id.present?)
18
+ end
19
+ end
20
+ end
21
+
22
+ def photos(query = {})
23
+ if @orders && query.blank?
24
+ @orders.to_a
25
+ else
26
+ Order.where(query.merge("#{ self.class.name.demodulize.underscore }_id" => id))
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ require 'active_support/concern'
2
+
3
+ module Fera
4
+ module HasManyReviews
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ has_many :reviews, class_name: "Fera::Review"
9
+ end
10
+
11
+ def reviews=(new_reviews)
12
+ @reviews = new_reviews.to_a.map do |model|
13
+ if model.is_a?(Review)
14
+ model
15
+ else
16
+ model_id = model.try(:with_indifferent_access).try(:[], :id)
17
+ Review.new(model, model_id.present?)
18
+ end
19
+ end
20
+ end
21
+
22
+ def reviews(query = {})
23
+ if @reviews && query.blank?
24
+ @reviews.to_a
25
+ else
26
+ Review.where(query.merge("#{ self.class.name.demodulize.underscore }_id" => id))
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ require 'active_support/concern'
2
+
3
+ module Fera
4
+ module HasManySubmissions
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ has_many :submission, class_name: "Fera::Submission"
9
+ end
10
+
11
+ def submissions=(new_submissions)
12
+ @submissions = new_submissions.to_a.map do |model|
13
+ if model.is_a?(Submission)
14
+ model
15
+ else
16
+ model_id = model.try(:with_indifferent_access).try(:[], :id)
17
+ Submission.new(model, model_id.present?)
18
+ end
19
+ end
20
+ end
21
+
22
+ def submissions(query = {})
23
+ if @submissions && query.blank?
24
+ @submissions.to_a
25
+ else
26
+ Submission.where(query.merge("#{ self.class.name.demodulize.underscore }_id" => id))
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,95 @@
1
+ require 'active_support/concern'
2
+
3
+ module Fera
4
+ module HasMedia
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ has_many :media, class_name: "Fera::Media"
9
+ has_many :videos, class_name: "Fera::Video"
10
+ has_many :photos, class_name: "Fera::Photo"
11
+ end
12
+
13
+ def media=(inputs)
14
+ @media = inputs.to_a.map do |input|
15
+ self.new_media(input)
16
+ end
17
+ end
18
+
19
+ def add_media(input)
20
+ new_model = self.new_media(input)
21
+ if @media.nil?
22
+ @media = [new_model]
23
+ else
24
+ @media << new_model
25
+ end
26
+ end
27
+
28
+ def new_media(input = nil)
29
+ model_class = [Photo, Video].include?(input.class) ? input.class : Media
30
+ new_has_many_associated_model(model_class, input)
31
+ end
32
+
33
+ def media(query = {})
34
+ if @media && query.blank?
35
+ @media.to_a
36
+ else
37
+ Media.where(query.merge("#{ self.class.name.demodulize.underscore }_id" => id))
38
+ end
39
+ end
40
+
41
+ def photos=(inputs)
42
+ @photos = inputs.to_a.map do |input|
43
+ new_has_many_associated_model(Photo, input)
44
+ end
45
+ end
46
+
47
+ def add_photo(input)
48
+ new_model = self.new_photo(input)
49
+ if @photos.nil?
50
+ @photos = [new_model]
51
+ else
52
+ @photos << new_model
53
+ end
54
+ end
55
+
56
+ def new_photo(input = nil)
57
+ new_has_many_associated_model(Photo, input)
58
+ end
59
+
60
+ def photos(query = {})
61
+ if @photos && query.blank?
62
+ @photos.to_a
63
+ else
64
+ Photo.where(query.merge("#{ self.class.name.demodulize.underscore }_id" => id))
65
+ end
66
+ end
67
+
68
+ def videos=(inputs)
69
+ @videos = inputs.to_a.map do |input|
70
+ self.new_video(input)
71
+ end
72
+ end
73
+
74
+ def add_video(input)
75
+ new_model = self.new_video(input)
76
+ if @videos.nil?
77
+ @videos = [new_model]
78
+ else
79
+ @videos << new_model
80
+ end
81
+ end
82
+
83
+ def new_video(input = nil)
84
+ new_has_many_associated_model(Video, input)
85
+ end
86
+
87
+ def videos(query = {})
88
+ if @videos && query.blank?
89
+ @videos.to_a
90
+ else
91
+ Video.where(query.merge("#{ self.class.name.demodulize.underscore }_id" => id))
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,44 @@
1
+ require 'active_support/concern'
2
+
3
+ module Fera
4
+ module HasSubject
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ def for_products(product_ids = nil)
9
+ if product_ids.present?
10
+ where(product_id: product_ids)
11
+ else
12
+ where(subject: :product)
13
+ end
14
+ end
15
+
16
+ def for_product(product_id)
17
+ for_products(product_id).try(:first)
18
+ end
19
+
20
+ def for_store
21
+ all.where(subject: :store).try(:first)
22
+ end
23
+ end
24
+
25
+ ##
26
+ # Returns the associated product model if it was preloaded in the original request and if the object is for a product.
27
+ # @return [::Fera::Product, NilClass]
28
+ def product
29
+ if attributes['subject'] =~ /^product/i
30
+ super
31
+ else
32
+ nil
33
+ end
34
+ end
35
+
36
+ def for_product?
37
+ subject.to_s == 'product'
38
+ end
39
+
40
+ def for_store?
41
+ subject.to_s == 'store'
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,8 @@
1
+ module Fera
2
+ class Customer < Base
3
+ include HasManyReviews
4
+ include HasMedia
5
+ include HasManyOrders
6
+ include HasManySubmissions
7
+ end
8
+ end
@@ -0,0 +1,55 @@
1
+ module Fera
2
+ class Media < Base
3
+ include HasSubject
4
+ include BelongsToCustomer
5
+ include BelongsToProduct
6
+ include BelongsToReview
7
+ include BelongsToSubmission
8
+
9
+ after_create :remove_file_param
10
+
11
+ class << self
12
+ def instantiate_record(record, prefix_options = {})
13
+ new_klass = if record['type'] == 'video'
14
+ Video
15
+ else
16
+ Photo
17
+ end
18
+ new_klass.new(record, record['id'].present?).tap do |resource|
19
+ resource.prefix_options = prefix_options
20
+ end
21
+ end
22
+ end
23
+
24
+ def is_video?
25
+ type.to_s == 'video'
26
+ end
27
+ alias_method :video?, :is_video?
28
+
29
+ def is_photo?
30
+ type.to_s == 'photo'
31
+ end
32
+ alias_method :photo?, :is_photo?
33
+
34
+ def file=(f)
35
+ if f.is_a?(File)
36
+ file_name = File.basename(f.path)
37
+ mime_type_group = type == 'video' ? 'video' : 'image'
38
+ self.attributes['file'] = {
39
+ 'name' => File.basename(file_name),
40
+ 'data' => "data:#{ mime_type_group }/#{ file_name.split('.').last };base64,#{ Base64.encode64(f.read) }"
41
+ }
42
+ else
43
+ self.attributes['file'] = f
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def remove_file_param
50
+ if self.attributes.key?('file')
51
+ self.attributes.delete('file')
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,5 @@
1
+ module Fera
2
+ class Order < Base
3
+ include BelongsToCustomer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Fera
2
+ class Photo < Media
3
+ def type; 'video'; end
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ module Fera
2
+ class Product < Base
3
+ include HasManyReviews
4
+ include HasMedia
5
+
6
+ alias_attribute :rating, :average_rating
7
+
8
+ def self.ratings(query = {})
9
+ ProductRating.where(query)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ module Fera
2
+ class Rating < Base
3
+ include HasSubject
4
+ include BelongsToProduct
5
+
6
+ alias_attribute :value, :average
7
+ alias_attribute :rating, :average
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ module Fera
2
+ class Review < Base
3
+ include HasMedia
4
+ include HasSubject
5
+ include BelongsToCustomer
6
+ include BelongsToProduct
7
+ include BelongsToSubmission
8
+
9
+ def only_rating?
10
+ body.blank? && heading.blank?
11
+ end
12
+ alias_method :rating_only?, :only_rating?
13
+
14
+ def stars
15
+ (('★' * rating) + ('☆' * (5 - rating))).chars.join(" ")
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ module Fera
2
+ class Store < Base
3
+ include ActiveResource::Singleton
4
+
5
+ self.singleton_name = :store
6
+
7
+ def self.current(options = {})
8
+ find(options)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ module Fera
2
+ class Submission < Base
3
+ include HasMedia
4
+ include HasManyReviews
5
+ include BelongsToCustomer
6
+ include BelongsToOrder
7
+
8
+ schema do
9
+ string 'id'
10
+ string 'external_customer_id'
11
+ string 'customer_id'
12
+
13
+ boolean 'is_test'
14
+
15
+ timestamp 'created_at'
16
+ timestamp 'updated_at'
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ module Fera
2
+ class Video < Media
3
+ def type; 'video'; end
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module Fera
2
+ class Webhook < Base
3
+ end
4
+ end
data/lib/fera.rb ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fera
4
+ end