backframe 0.0.49 → 1.0.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 +4 -4
- data/.codeclimate.yml +16 -0
- data/.gitignore +2 -2
- data/.rspec +2 -0
- data/.rubocop.yml +1156 -0
- data/Gemfile +9 -13
- data/README.md +133 -4
- data/Rakefile +3 -7
- data/backframe.gemspec +10 -11
- data/circle.yml +5 -2
- data/lib/backframe.rb +21 -34
- data/lib/backframe/mime.rb +4 -0
- data/lib/backframe/query.rb +48 -0
- data/lib/backframe/query/sort.rb +29 -0
- data/lib/backframe/railtie.rb +1 -16
- data/lib/backframe/response.rb +60 -0
- data/lib/backframe/response/adapter/csv.rb +39 -0
- data/lib/backframe/response/adapter/json.rb +53 -0
- data/lib/backframe/response/adapter/xlsx.rb +41 -0
- data/lib/backframe/response/adapter/xml.rb +37 -0
- data/lib/backframe/response/collection.rb +43 -0
- data/lib/backframe/response/fields.rb +62 -0
- data/lib/backframe/response/record.rb +38 -0
- data/lib/backframe/service.rb +60 -0
- data/lib/backframe/service/result/base.rb +24 -0
- data/lib/backframe/service/result/failure.rb +21 -0
- data/lib/backframe/service/result/success.rb +21 -0
- data/lib/backframe/version.rb +1 -1
- data/spec/fixtures/active_record.rb +22 -0
- data/spec/fixtures/models.rb +25 -0
- data/spec/fixtures/queries.rb +28 -0
- data/spec/fixtures/seeds.rb +12 -0
- data/spec/fixtures/serializers.rb +23 -0
- data/spec/fixtures/services.rb +26 -0
- data/spec/query/sort_spec.rb +47 -0
- data/spec/query_spec.rb +63 -0
- data/spec/response/adapter/csv_spec.rb +47 -0
- data/spec/response/adapter/json_spec.rb +66 -0
- data/spec/response/adapter/xlsx_spec.rb +59 -0
- data/spec/response/adapter/xml_spec.rb +63 -0
- data/spec/response/fields_spec.rb +45 -0
- data/spec/response/record_spec.rb +45 -0
- data/spec/response_spec.rb +153 -0
- data/spec/service/result/failure_spec.rb +16 -0
- data/spec/service/result/sucess_spec.rb +17 -0
- data/spec/service_spec.rb +16 -0
- data/spec/spec_helper.rb +15 -52
- metadata +78 -81
- data/lib/backframe/actioncontroller/acts_as_activation.rb +0 -70
- data/lib/backframe/actioncontroller/acts_as_api.rb +0 -39
- data/lib/backframe/actioncontroller/acts_as_api/adapter.rb +0 -53
- data/lib/backframe/actioncontroller/acts_as_api/errors.rb +0 -48
- data/lib/backframe/actioncontroller/acts_as_api/headers.rb +0 -11
- data/lib/backframe/actioncontroller/acts_as_api/page.rb +0 -181
- data/lib/backframe/actioncontroller/acts_as_reset.rb +0 -86
- data/lib/backframe/actioncontroller/acts_as_resource.rb +0 -92
- data/lib/backframe/actioncontroller/acts_as_resource/actions.rb +0 -100
- data/lib/backframe/actioncontroller/acts_as_session.rb +0 -80
- data/lib/backframe/activerecord/acts_as_activable.rb +0 -50
- data/lib/backframe/activerecord/acts_as_distinct.rb +0 -49
- data/lib/backframe/activerecord/acts_as_enum.rb +0 -62
- data/lib/backframe/activerecord/acts_as_orderable.rb +0 -40
- data/lib/backframe/activerecord/acts_as_percent.rb +0 -46
- data/lib/backframe/activerecord/acts_as_phone.rb +0 -59
- data/lib/backframe/activerecord/acts_as_user.rb +0 -101
- data/lib/backframe/activerecord/default_values.rb +0 -32
- data/lib/backframe/activerecord/filter_sort.rb +0 -79
- data/lib/backframe/activerecord/migration.rb +0 -25
- data/lib/backframe/image_cache/image_cache.rb +0 -45
- data/lib/backframe/image_cache/lib/asset.rb +0 -109
- data/lib/backframe/image_cache/lib/cache.rb +0 -67
- data/lib/backframe/image_cache/lib/conversions.rb +0 -132
- data/lib/backframe/models/activation.rb +0 -60
- data/lib/backframe/models/activity.rb +0 -40
- data/lib/backframe/models/reset.rb +0 -59
- data/lib/backframe/models/story.rb +0 -9
- data/lib/backframe/serializers/activity_serializer.rb +0 -44
- data/spec/backframe/acts_as_api_spec.rb +0 -225
- data/spec/backframe/acts_as_resource_spec.rb +0 -178
- data/spec/support/example_factory.rb +0 -9
- data/spec/support/example_serializer.rb +0 -3
- data/spec/support/schema.rb +0 -8
@@ -1,67 +0,0 @@
|
|
1
|
-
require 'stringio'
|
2
|
-
|
3
|
-
module Backframe
|
4
|
-
|
5
|
-
module ImageCache
|
6
|
-
|
7
|
-
class Cache
|
8
|
-
|
9
|
-
def initialize(filepath, conversions)
|
10
|
-
@filepath = filepath
|
11
|
-
@conversions = conversions
|
12
|
-
end
|
13
|
-
|
14
|
-
def process
|
15
|
-
begin
|
16
|
-
test(filepath, conversions)
|
17
|
-
rescue
|
18
|
-
test(nil, conversions)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def test(filepath, conversions)
|
23
|
-
filekey = filepath || 'default.jpg'
|
24
|
-
normalized = Backframe::ImageCache::Conversions.new(conversions)
|
25
|
-
key = "imagecache/#{normalized.to_s}/#{filekey}"
|
26
|
-
if !redis.get(key)
|
27
|
-
asset = Backframe::ImageCache::Asset.new(filepath, normalized).process
|
28
|
-
upload_to_s3(asset, key)
|
29
|
-
save_to_redis(key)
|
30
|
-
end
|
31
|
-
return OpenStruct.new(:success => true, :url => "#{Rails.application.config.cdn_url}/#{key}")
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
attr_reader :filepath, :conversions
|
37
|
-
|
38
|
-
def save_to_redis(key)
|
39
|
-
redis.set(key, true)
|
40
|
-
redis.expire(key, (7 * 24 * 60 * 60))
|
41
|
-
end
|
42
|
-
|
43
|
-
def upload_to_s3(asset, key)
|
44
|
-
headers = { :acl => 'public-read', :content_type => asset.content_type, :cache_control => 'max-age=315360000, no-transform, public', :content_encoding => 'gzip' }
|
45
|
-
bucket = s3.buckets[aws['bucket']]
|
46
|
-
bucket.objects.create(key, asset.data, headers)
|
47
|
-
end
|
48
|
-
|
49
|
-
def aws
|
50
|
-
@aws ||= YAML.load_file("#{Rails.root}/config/aws.yml")[Rails.env]
|
51
|
-
end
|
52
|
-
|
53
|
-
def s3
|
54
|
-
@s3 ||= AWS::S3.new(:access_key_id => aws['access_key_id'], :secret_access_key => aws['secret_access_key'])
|
55
|
-
end
|
56
|
-
|
57
|
-
def redis
|
58
|
-
return @redis if @redis.present?
|
59
|
-
config = YAML.load_file("#{Rails.root}/config/redis.yml")[Rails.env]
|
60
|
-
@redis = Redis.new(:host => config['host'], :port => config['port'], :db => config[:cache])
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
end
|
@@ -1,132 +0,0 @@
|
|
1
|
-
require 'stringio'
|
2
|
-
|
3
|
-
module Backframe
|
4
|
-
|
5
|
-
module ImageCache
|
6
|
-
|
7
|
-
class Conversions
|
8
|
-
|
9
|
-
def initialize(conversions)
|
10
|
-
@conversions = normalize_conversions(conversions)
|
11
|
-
end
|
12
|
-
|
13
|
-
def to_s
|
14
|
-
output = []
|
15
|
-
conversions.each do |conversion|
|
16
|
-
if conversion.key?(:fit)
|
17
|
-
output << "F#{conversion[:fit][:width]}X#{conversion[:fit][:height]}D#{conversion[:density]}"
|
18
|
-
elsif conversion.key?(:width)
|
19
|
-
output << "W#{conversion[:width]}D#{conversion[:density]}"
|
20
|
-
elsif conversion.key?(:height)
|
21
|
-
output << "H#{conversion[:height]}D#{conversion[:density]}"
|
22
|
-
elsif conversion.key?(:crop)
|
23
|
-
output << "C#{conversion[:crop][:width]}X#{conversion[:crop][:height]}X#{conversion[:crop][:x]}X#{conversion[:crop][:y]}D#{conversion[:density]}"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
output.join("-")
|
27
|
-
end
|
28
|
-
|
29
|
-
def to_a
|
30
|
-
conversions
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
attr_reader :conversions
|
36
|
-
|
37
|
-
#################### CONVERSION HANDLING ####################
|
38
|
-
|
39
|
-
def normalize_conversions(conversions)
|
40
|
-
if conversions.is_a?(String)
|
41
|
-
return normalize_conversion_string(conversions)
|
42
|
-
elsif conversions.is_a?(Symbol)
|
43
|
-
return normalize_conversion_string(conversions.to_s)
|
44
|
-
elsif conversions.is_a?(Hash)
|
45
|
-
return normalize_conversion_array([conversions])
|
46
|
-
elsif conversions.is_a?(Array)
|
47
|
-
return normalize_conversion_array(conversions)
|
48
|
-
elsif conversions.is_a?(Backframe::ImageCache::Conversions)
|
49
|
-
return conversions.to_a
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def normalize_conversion_string(string)
|
54
|
-
output = []
|
55
|
-
string.upcase.split("-").each do |part|
|
56
|
-
if part == 'PREVIEW'
|
57
|
-
output << { :width => 250, :density => 2 }
|
58
|
-
elsif part == 'TINY'
|
59
|
-
output << { :fit => { :width => 20, :height => 20 }, :density => 2 }
|
60
|
-
elsif part == 'SMALL'
|
61
|
-
output << { :fit => { :width => 40, :height => 40 }, :density => 2 }
|
62
|
-
elsif part == 'MEDIUM'
|
63
|
-
output << { :fit => { :width => 250, :height => 250 }, :density => 2 }
|
64
|
-
elsif matches = part.match(/^F(\d*)X(\d*)(D(\d*))?$/)
|
65
|
-
density = (matches[3]) ? matches[4] : 1
|
66
|
-
output << { :fit => { :width => matches[1].to_i, :height => matches[2].to_i }, :density => density.to_i }
|
67
|
-
elsif matches = part.match(/^W(\d*)(D(\d*))?$/)
|
68
|
-
density = (matches[2]) ? matches[3] : 1
|
69
|
-
output << { :width => matches[1].to_i, :density => density.to_i }
|
70
|
-
elsif matches = part.match(/^H(\d*)(D(\d*))?$/)
|
71
|
-
density = (matches[2]) ? matches[3] : 1
|
72
|
-
output << { :height => matches[1].to_i, :density => density.to_i }
|
73
|
-
elsif matches = part.match(/^C(\d*)X(\d*)X(\d*)X(\d*)(D(\d*))?$/)
|
74
|
-
density = (matches[4]) ? matches[5] : 1
|
75
|
-
output << { :crop => { :width => matches[1].to_i, :height => matches[2].to_i, :x => matches[3].to_i, :y => matches[4].to_i, :density => density.to_i } }
|
76
|
-
end
|
77
|
-
end
|
78
|
-
output
|
79
|
-
end
|
80
|
-
|
81
|
-
def normalize_conversion_array(array)
|
82
|
-
output = []
|
83
|
-
array.each do |conversion|
|
84
|
-
density = conversion[:density].to_i || 1
|
85
|
-
if conversion.key?(:preview)
|
86
|
-
output << { :width => 250, :density => density }
|
87
|
-
elsif conversion.key?(:tiny)
|
88
|
-
output << { :fit => { :width => 20, :height => 20 }, :density => density }
|
89
|
-
elsif conversion.key?(:small)
|
90
|
-
output << { :fit => { :width => 40, :height => 40 }, :density => density }
|
91
|
-
elsif conversion.key?(:medium)
|
92
|
-
output << { :fit => { :width => 250, :height => 250 }, :density => density }
|
93
|
-
elsif conversion.key?(:fit)
|
94
|
-
fit = (conversion[:fit].is_a?(String)) ? parse_geometry_string(conversion[:fit]) : parse_geometry_array(conversion[:fit])
|
95
|
-
output << { :fit => fit, :density => density }
|
96
|
-
elsif conversion.key?(:width)
|
97
|
-
output << { :width => conversion[:width].to_i, :density => density }
|
98
|
-
elsif conversion.key?(:height)
|
99
|
-
output << { :height => conversion[:height].to_i, :density => density }
|
100
|
-
elsif conversion.key?(:crop)
|
101
|
-
crop = (conversion[:crop].is_a?(String)) ? parse_geometry(conversion[:crop]) : parse_geometry_array(conversion[:crop])
|
102
|
-
output << { :crop => crop, :density => density }
|
103
|
-
end
|
104
|
-
end
|
105
|
-
output
|
106
|
-
end
|
107
|
-
|
108
|
-
def parse_geometry_string(string)
|
109
|
-
string = string.upcase
|
110
|
-
if matches = string.match(/^(\d*)X(\d*)$/)
|
111
|
-
{ :width => matches[1].to_i, :height => matches[2].to_i }
|
112
|
-
elsif matches = string.match(/^(\d*)X(\d*)X(\d*)X(\d*)$/)
|
113
|
-
{ :width => matches[1].to_i, :height => matches[2].to_i, :x => matches[3].to_i, :y => matches[4].to_i }
|
114
|
-
elsif matches = string.match(/^(\d*)X(\d*)\+(\d*)\+(\d*)$/)
|
115
|
-
{ :width => matches[1].to_i, :height => matches[2].to_i, :x => matches[3].to_i, :y => matches[4].to_i }
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def parse_geometry_array(array)
|
120
|
-
output = {}
|
121
|
-
output[:width] = array[:width].to_i if array.key?(:width)
|
122
|
-
output[:height] = array[:height].to_i if array.key?(:height)
|
123
|
-
output[:x] = array[:x].to_i if array.key?(:x)
|
124
|
-
output[:y] = array[:y].to_i if array.key?(:y)
|
125
|
-
output
|
126
|
-
end
|
127
|
-
|
128
|
-
end
|
129
|
-
|
130
|
-
end
|
131
|
-
|
132
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Backframe
|
4
|
-
class Activation < ActiveRecord::Base
|
5
|
-
|
6
|
-
liquid_methods :code, :url
|
7
|
-
|
8
|
-
belongs_to :user, :polymorphic => true
|
9
|
-
|
10
|
-
validates_presence_of :user, :token
|
11
|
-
|
12
|
-
after_initialize :init, :if => Proc.new { |o| o.new_record? }
|
13
|
-
after_create :enforce_uniqueness
|
14
|
-
after_commit :send_email
|
15
|
-
|
16
|
-
def claim
|
17
|
-
self.claimed_at = Time.zone.now
|
18
|
-
self.is_active = false
|
19
|
-
self.save
|
20
|
-
self.user.update_attributes(:is_active => true, :activated_at => Time.zone.now)
|
21
|
-
end
|
22
|
-
|
23
|
-
def expired?
|
24
|
-
!self.is_active
|
25
|
-
end
|
26
|
-
|
27
|
-
def url
|
28
|
-
return "#{Rails.application.config.root_url}/admin/activation/#{self.token}" if self.user_type == 'Admin'
|
29
|
-
return "#{Rails.application.config.root_url}/account/activation/#{self.token}" if self.user_type == 'Customer'
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def init
|
35
|
-
self.token ||= SecureRandom.hex(32).to_s.upcase[0,32]
|
36
|
-
self.is_active = true
|
37
|
-
end
|
38
|
-
|
39
|
-
def set_active
|
40
|
-
self.is_active = true
|
41
|
-
end
|
42
|
-
|
43
|
-
def enforce_uniqueness
|
44
|
-
self.user.activations.where('id != ?', self.id).update_all(:is_active => false)
|
45
|
-
end
|
46
|
-
|
47
|
-
def send_email
|
48
|
-
return if Rails.env.test?
|
49
|
-
if self.user_type == 'Admin'
|
50
|
-
ApplicationMailer.activation(self).deliver_now!
|
51
|
-
elsif self.user_type == 'Customer'
|
52
|
-
template = EmailTemplate.find_by(:code => 'account_activation')
|
53
|
-
email = EmailDelivery.new(:customer => self.user, :subject => template.subject, :body => template.body)
|
54
|
-
email.personalize(:customer => self.user, :activation => self)
|
55
|
-
email.save
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Backframe
|
4
|
-
class Activity < ActiveRecord::Base
|
5
|
-
|
6
|
-
belongs_to :subject, :polymorphic => true
|
7
|
-
belongs_to :object1, :polymorphic => true
|
8
|
-
belongs_to :object2, :polymorphic => true
|
9
|
-
belongs_to :story
|
10
|
-
|
11
|
-
validates_presence_of :story, :subject
|
12
|
-
|
13
|
-
default_scope -> { includes(:subject,:object1,:object2,:story).order(:created_at => :desc) }
|
14
|
-
|
15
|
-
def text=(text)
|
16
|
-
self.story = Backframe::Story.find_or_initialize_by(:text => text)
|
17
|
-
end
|
18
|
-
|
19
|
-
def subject=(object)
|
20
|
-
self.subject_type = object.class.name
|
21
|
-
self.subject_text = object.activity_text
|
22
|
-
self.subject_id = object.id
|
23
|
-
end
|
24
|
-
|
25
|
-
def object1=(object)
|
26
|
-
self.object1_type = object.class.name
|
27
|
-
self.object1_text = object.activity_text
|
28
|
-
self.object1_id = object.id
|
29
|
-
object
|
30
|
-
end
|
31
|
-
|
32
|
-
def object2=(object)
|
33
|
-
self.object2_type = object.class.name
|
34
|
-
self.object2_text = object.activity_text
|
35
|
-
self.object2_id = object.id
|
36
|
-
object
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
end
|
@@ -1,59 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Backframe
|
4
|
-
class Reset < ActiveRecord::Base
|
5
|
-
|
6
|
-
liquid_methods :code, :url
|
7
|
-
|
8
|
-
belongs_to :user, :polymorphic => true
|
9
|
-
|
10
|
-
validates_presence_of :user, :token
|
11
|
-
|
12
|
-
after_initialize :init, :if => Proc.new { |o| o.new_record? }
|
13
|
-
after_create :enforce_uniqueness
|
14
|
-
after_commit :send_email
|
15
|
-
|
16
|
-
def claim
|
17
|
-
self.claimed_at = Time.zone.now
|
18
|
-
self.is_active = false
|
19
|
-
self.save
|
20
|
-
self.user.update_attributes(:is_active => true, :activated_at => Time.zone.now)
|
21
|
-
end
|
22
|
-
|
23
|
-
def expired?
|
24
|
-
!self.is_active
|
25
|
-
end
|
26
|
-
|
27
|
-
def url
|
28
|
-
return "#{Rails.application.config.root_url}/admin/reset/#{self.token}" if self.user_type == 'Admin'
|
29
|
-
return "#{Rails.application.config.root_url}/account/reset/#{self.token}" if self.user_type == 'Customer'
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def init
|
35
|
-
self.token ||= SecureRandom.hex(32).to_s.upcase[0,32]
|
36
|
-
self.is_active = true
|
37
|
-
end
|
38
|
-
|
39
|
-
def set_active
|
40
|
-
self.is_active = true
|
41
|
-
end
|
42
|
-
|
43
|
-
def enforce_uniqueness
|
44
|
-
self.user.resets.where('id != ?', self.id).update_all(:is_active => false)
|
45
|
-
end
|
46
|
-
|
47
|
-
def send_email
|
48
|
-
if self.user_type == 'Admin'
|
49
|
-
ApplicationMailer.reset(self).deliver_now!
|
50
|
-
elsif self.user_type == 'Customer'
|
51
|
-
template = EmailTemplate.find_by(:code => 'password_reset')
|
52
|
-
email = EmailDelivery.new(:customer => self.user, :subject => template.subject, :body => template.body)
|
53
|
-
email.personalize(:customer => self.user, :reset => self)
|
54
|
-
email.save
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Backframe
|
4
|
-
class ActivitySerializer < ActiveModel::Serializer
|
5
|
-
|
6
|
-
cache :key => :object
|
7
|
-
attributes :id, :subject, :story, :object1, :object2, :created_at, :updated_at
|
8
|
-
|
9
|
-
def subject
|
10
|
-
if object.subject.present?
|
11
|
-
{ :link => object.subject.activity_link, :photo => (object.subject.photo.present?) ? object.subject.photo.url(:small) : nil, :text => object.subject.full_name }
|
12
|
-
elsif object.subject_text.present?
|
13
|
-
{ :text => object.subject_text }
|
14
|
-
else
|
15
|
-
nil
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def story
|
20
|
-
object.story.text
|
21
|
-
end
|
22
|
-
|
23
|
-
def object1
|
24
|
-
if object.object1.present?
|
25
|
-
{ :link => object.object1.activity_link, :entity => object.object1.activity_entity, :text => object.object1.activity_text }
|
26
|
-
elsif object.object1_text.present?
|
27
|
-
{ :text => object.object1_text }
|
28
|
-
else
|
29
|
-
nil
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def object2
|
34
|
-
if object.object2.present?
|
35
|
-
{ :link => object.object2.activity_link, :entity => object.object2.activity_entity, :text => object.object2.activity_text }
|
36
|
-
elsif object.object2_text.present?
|
37
|
-
{ :text => object.object2_text }
|
38
|
-
else
|
39
|
-
nil
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
@@ -1,225 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'Backframe::ActsAsAPI', type: :controller do
|
4
|
-
controller do
|
5
|
-
include Backframe::ActsAsAPI
|
6
|
-
acts_as_api
|
7
|
-
|
8
|
-
def base_api_url
|
9
|
-
'/example'
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
describe 'error handlng' do
|
14
|
-
before { get :index }
|
15
|
-
|
16
|
-
context 'acts_as_resource not found' do
|
17
|
-
controller do
|
18
|
-
def index
|
19
|
-
raise ActiveRecord::RecordNotFound
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'responds with 404 status' do
|
24
|
-
expect(response.status).to eq 404
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'responds with JSON body' do
|
28
|
-
expect(json_response[:error][:status]).to eq 404
|
29
|
-
expect(json_response[:error][:message]).to be
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
context 'route not found' do
|
34
|
-
controller do
|
35
|
-
def index
|
36
|
-
raise ActionController::RoutingError, ''
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'responds with 404 status' do
|
41
|
-
expect(response.status).to eq 404
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'responds with JSON body' do
|
45
|
-
expect(json_response[:error][:status]).to eq 404
|
46
|
-
expect(json_response[:error][:message]).to be
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context 'unauthenticated' do
|
51
|
-
controller do
|
52
|
-
def index
|
53
|
-
raise Backframe::Exceptions::Unauthenticated
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
it 'responds with 401 status' do
|
58
|
-
expect(response.status).to eq 401
|
59
|
-
end
|
60
|
-
|
61
|
-
it 'responds with JSON body' do
|
62
|
-
expect(json_response[:error][:status]).to eq 401
|
63
|
-
expect(json_response[:error][:message]).to be
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
context 'unauthorized' do
|
68
|
-
controller do
|
69
|
-
def index
|
70
|
-
raise Backframe::Exceptions::Unauthorized
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
it 'responds with 403 status' do
|
75
|
-
expect(response.status).to eq 403
|
76
|
-
end
|
77
|
-
|
78
|
-
it 'responds with JSON body' do
|
79
|
-
expect(json_response[:error][:status]).to eq 403
|
80
|
-
expect(json_response[:error][:message]).to be
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
describe 'headers' do
|
86
|
-
controller do
|
87
|
-
def index
|
88
|
-
render nothing: true
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'responds with Last-Modified header' do
|
93
|
-
get :index
|
94
|
-
|
95
|
-
# FIXME: Use timecop here
|
96
|
-
expect(response.headers['Last-Modified']).to eq Time.now.httpdate
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
describe '#page' do
|
101
|
-
let!(:records) { create_list(:example, 10) }
|
102
|
-
|
103
|
-
controller do
|
104
|
-
def index
|
105
|
-
page(Example.all, nil)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'responds with 200 status' do
|
110
|
-
get :index, format: :json
|
111
|
-
expect(response.status).to eq 200
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'responds with records' do
|
115
|
-
get :index, format: :json
|
116
|
-
expect(json_response[:records].length).to eq 10
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'responds with links' do
|
120
|
-
get :index, format: :json
|
121
|
-
expect(json_response[:links]).to be
|
122
|
-
expect(json_response[:links][:self]).to eq '/example/anonymous.json?page=1'
|
123
|
-
end
|
124
|
-
|
125
|
-
context 'with pagination params' do
|
126
|
-
before { get :index, page: 2, per_page: 3, format: :json }
|
127
|
-
|
128
|
-
it 'serializes one page of records' do
|
129
|
-
expect(json_response[:records].length).to eq 3
|
130
|
-
|
131
|
-
serialized = serialize(Example.sort(Example)[3]).stringify_keys
|
132
|
-
expect(json_response[:records].first).to eq serialized
|
133
|
-
end
|
134
|
-
|
135
|
-
it 'includes pagination metadata' do
|
136
|
-
expect(json_response[:total_records]).to eq 10
|
137
|
-
expect(json_response[:total_pages]).to eq 4
|
138
|
-
expect(json_response[:current_page]).to eq 2
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
context 'without pagination params' do
|
143
|
-
before { get :index, format: :json }
|
144
|
-
|
145
|
-
it 'serializes all records' do
|
146
|
-
expect(json_response[:records].length).to eq 10
|
147
|
-
|
148
|
-
serialized = serialize(Example.sort(Example).first).stringify_keys
|
149
|
-
expect(json_response[:records].first).to eq serialized
|
150
|
-
end
|
151
|
-
|
152
|
-
it 'includes pagination metadata' do
|
153
|
-
expect(json_response[:total_records]).to eq 10
|
154
|
-
expect(json_response[:total_pages]).to eq 1
|
155
|
-
expect(json_response[:current_page]).to eq 1
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
context 'with sort params' do
|
160
|
-
controller do
|
161
|
-
def index
|
162
|
-
page(Example.all)
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
context 'with single param' do
|
167
|
-
before do
|
168
|
-
create_list(:example, 10)
|
169
|
-
get :index, sort: 'a', format: :json
|
170
|
-
end
|
171
|
-
|
172
|
-
it 'responds with records sorted ascending' do
|
173
|
-
values = json_response[:records].map { |record| record[:a] }
|
174
|
-
expect(values).to eq values.sort
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
context 'with negated param' do
|
179
|
-
before do
|
180
|
-
create_list(:example, 10)
|
181
|
-
get :index, sort: '-a', format: :json
|
182
|
-
end
|
183
|
-
|
184
|
-
it 'responds with records sorted descending' do
|
185
|
-
values = json_response[:records].map { |record| record[:a] }
|
186
|
-
expect(values).to eq values.sort.reverse
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
context 'with multiple params' do
|
191
|
-
before do
|
192
|
-
create_list(:example, 10, a: 'a')
|
193
|
-
create_list(:example, 10)
|
194
|
-
get :index, sort: 'a,b', format: :json
|
195
|
-
end
|
196
|
-
|
197
|
-
it 'responds with records sorted by both fields' do
|
198
|
-
values = json_response[:records].map { |record| [record[:a], record[:b]] }
|
199
|
-
expect(values).to eq values.sort
|
200
|
-
end
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
context 'with field params' do
|
205
|
-
let!(:records) { create_list(:example, 10) }
|
206
|
-
|
207
|
-
before { get :index, fields: 'a,b', format: :json }
|
208
|
-
|
209
|
-
it 'only responds with given fields' do
|
210
|
-
expect(json_response[:records].first).to eq serialize(Example.sort(Example).first, fields: [:a, :b]).stringify_keys
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
context 'with exclude ids params' do
|
215
|
-
let!(:records) { create_list(:example, 10) }
|
216
|
-
let(:exclude_ids) { records.take(5).map(&:id).join(',') }
|
217
|
-
|
218
|
-
before { get :index, exclude_ids: exclude_ids, format: :json }
|
219
|
-
|
220
|
-
it 'responds with unexcluded records' do
|
221
|
-
expect(json_response[:records].length).to eq 5
|
222
|
-
end
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end
|