backframe 0.0.49 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|