populate-me 0.12.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 +7 -0
- data/.gitignore +9 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +655 -0
- data/Rakefile +14 -0
- data/example/config.ru +100 -0
- data/lib/populate_me.rb +2 -0
- data/lib/populate_me/admin.rb +157 -0
- data/lib/populate_me/admin/__assets__/css/asmselect.css +63 -0
- data/lib/populate_me/admin/__assets__/css/jquery-ui.min.css +6 -0
- data/lib/populate_me/admin/__assets__/css/main.css +244 -0
- data/lib/populate_me/admin/__assets__/img/help/children.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/create.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/delete.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/edit.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/form.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/list.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/login.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/logout.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/menu.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/overview.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/save.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/sort.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/sublist.png +0 -0
- data/lib/populate_me/admin/__assets__/js/asmselect.js +412 -0
- data/lib/populate_me/admin/__assets__/js/columnav.js +87 -0
- data/lib/populate_me/admin/__assets__/js/jquery-ui.min.js +7 -0
- data/lib/populate_me/admin/__assets__/js/main.js +388 -0
- data/lib/populate_me/admin/__assets__/js/mustache.js +578 -0
- data/lib/populate_me/admin/__assets__/js/sortable.js +2 -0
- data/lib/populate_me/admin/views/help.erb +94 -0
- data/lib/populate_me/admin/views/page.erb +189 -0
- data/lib/populate_me/api.rb +124 -0
- data/lib/populate_me/attachment.rb +186 -0
- data/lib/populate_me/document.rb +192 -0
- data/lib/populate_me/document_mixins/admin_adapter.rb +149 -0
- data/lib/populate_me/document_mixins/callbacks.rb +125 -0
- data/lib/populate_me/document_mixins/outcasting.rb +83 -0
- data/lib/populate_me/document_mixins/persistence.rb +95 -0
- data/lib/populate_me/document_mixins/schema.rb +198 -0
- data/lib/populate_me/document_mixins/typecasting.rb +70 -0
- data/lib/populate_me/document_mixins/validation.rb +44 -0
- data/lib/populate_me/file_system_attachment.rb +40 -0
- data/lib/populate_me/grid_fs_attachment.rb +103 -0
- data/lib/populate_me/mongo.rb +160 -0
- data/lib/populate_me/s3_attachment.rb +120 -0
- data/lib/populate_me/variation.rb +38 -0
- data/lib/populate_me/version.rb +4 -0
- data/populate-me.gemspec +34 -0
- data/test/helper.rb +37 -0
- data/test/test_admin.rb +183 -0
- data/test/test_api.rb +246 -0
- data/test/test_attachment.rb +167 -0
- data/test/test_document.rb +128 -0
- data/test/test_document_admin_adapter.rb +221 -0
- data/test/test_document_callbacks.rb +151 -0
- data/test/test_document_outcasting.rb +247 -0
- data/test/test_document_persistence.rb +83 -0
- data/test/test_document_schema.rb +280 -0
- data/test/test_document_typecasting.rb +128 -0
- data/test/test_grid_fs_attachment.rb +239 -0
- data/test/test_mongo.rb +324 -0
- data/test/test_s3_attachment.rb +281 -0
- data/test/test_variation.rb +91 -0
- data/test/test_version.rb +11 -0
- metadata +294 -0
data/populate-me.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'lib/populate_me/version')
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
|
5
|
+
s.authors = ["Mickael Riga"]
|
6
|
+
s.email = ["mig@mypeplum.com"]
|
7
|
+
s.homepage = "https://github.com/mig-hub/populate-me"
|
8
|
+
s.licenses = ['MIT']
|
9
|
+
|
10
|
+
s.name = 'populate-me'
|
11
|
+
s.version = PopulateMe::VERSION
|
12
|
+
s.summary = "PopulateMe is an admin system for web applications."
|
13
|
+
s.description = "PopulateMe is an admin system for managing structured content of web applications. It is built on top of the Sinatra framework, but can be used along any framework using Rack."
|
14
|
+
|
15
|
+
s.platform = Gem::Platform::RUBY
|
16
|
+
s.files = `git ls-files`.split("\n").sort
|
17
|
+
s.test_files = s.files.grep(/^test\//)
|
18
|
+
s.require_paths = ['lib']
|
19
|
+
|
20
|
+
s.add_dependency 'web-utils', '~> 0'
|
21
|
+
s.add_dependency 'sinatra', '~> 2'
|
22
|
+
s.add_dependency 'json', '~> 2.1'
|
23
|
+
|
24
|
+
s.add_development_dependency 'bundler', '~> 1.13'
|
25
|
+
s.add_development_dependency 'minitest', '~> 5.8'
|
26
|
+
s.add_development_dependency 'rack-test', '~> 0.6'
|
27
|
+
s.add_development_dependency 'rack-cerberus', '~> 1.0'
|
28
|
+
s.add_development_dependency 'mongo', '~> 2.0'
|
29
|
+
s.add_development_dependency 'rack-grid-serve', '~> 0.0.8'
|
30
|
+
s.add_development_dependency 'aws-sdk-s3', '~> 1'
|
31
|
+
s.add_development_dependency 'racksh', '~> 1.0'
|
32
|
+
s.add_development_dependency 'rake', '>= 12.3.3'
|
33
|
+
end
|
34
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'rack/test'
|
5
|
+
|
6
|
+
module Minitest::Assertions
|
7
|
+
def assert_json response
|
8
|
+
assert response.content_type=="application/json", "Expected #{response.inspect} to be a JSON response"
|
9
|
+
end
|
10
|
+
def assert_for_view json, view_name, title=nil
|
11
|
+
assert json['template']==view_name, "Expected #{json.inspect} to have 'template' set to '#{view_name}'"
|
12
|
+
unless title.nil?
|
13
|
+
assert json['page_title']==title, "Expected #{json.inspect} to have 'page_title' set to '#{title}'"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def assert_receive obj, meth, retval=nil, args=[]
|
18
|
+
mocked_meth = Minitest::Mock.new
|
19
|
+
mocked_meth.expect(:call, retval, args)
|
20
|
+
obj.stub meth, mocked_meth do
|
21
|
+
yield
|
22
|
+
end
|
23
|
+
assert mocked_meth.verify, "Expected #{obj.inspect} to receive :#{meth}"
|
24
|
+
end
|
25
|
+
def refute_receive obj, meth
|
26
|
+
proof = nil
|
27
|
+
obj.stub meth, proc{proof = :received} do
|
28
|
+
yield
|
29
|
+
assert(proof!=:received, "Expected #{obj.inspect} not to receive :#{meth}")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Minitest::Spec
|
35
|
+
include Rack::Test::Methods
|
36
|
+
end
|
37
|
+
|
data/test/test_admin.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'populate_me/admin'
|
3
|
+
|
4
|
+
class Admin < PopulateMe::Admin
|
5
|
+
enable :sessions
|
6
|
+
set :menu, [
|
7
|
+
['Home Details', '/admin/form/home-details/0'],
|
8
|
+
['Project Page', [
|
9
|
+
['Project Page Intro', '/admin/form/project-page-intro/0'],
|
10
|
+
['Projects', '/admin/list/project'],
|
11
|
+
['Checks', [
|
12
|
+
['Check 1', '/check/1'],
|
13
|
+
['Check 2', '/check/2']
|
14
|
+
]]
|
15
|
+
]]
|
16
|
+
]
|
17
|
+
end
|
18
|
+
|
19
|
+
class AdminWithCerberusPass < Admin
|
20
|
+
def self.cerberus_pass
|
21
|
+
'123'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class AdminCerberusNotAvailable < AdminWithCerberusPass
|
26
|
+
def self.cerberus_available?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class AdminCerberusDisabled < AdminWithCerberusPass
|
32
|
+
disable :cerberus
|
33
|
+
end
|
34
|
+
|
35
|
+
describe PopulateMe::Admin do
|
36
|
+
|
37
|
+
parallelize_me!
|
38
|
+
|
39
|
+
let(:app) { ::Admin.new }
|
40
|
+
|
41
|
+
let(:settings) { app.settings }
|
42
|
+
|
43
|
+
let(:json) { JSON.parse(last_response.body) }
|
44
|
+
|
45
|
+
describe 'Settings' do
|
46
|
+
it 'Sets paths based on the subclass file path' do
|
47
|
+
assert_equal __FILE__, settings.app_file
|
48
|
+
end
|
49
|
+
it 'Has a default value for the page title tag' do
|
50
|
+
assert_equal 'Populate Me', settings.meta_title
|
51
|
+
end
|
52
|
+
it 'Has a default index_path' do
|
53
|
+
assert_equal '/menu', settings.index_path
|
54
|
+
end
|
55
|
+
it 'Has cerberus enabled by default' do
|
56
|
+
assert settings.cerberus?
|
57
|
+
end
|
58
|
+
describe 'when ENV CERBERUS_PASS is not set' do
|
59
|
+
it 'Does not have cerberus_active' do
|
60
|
+
refute settings.cerberus_active
|
61
|
+
end
|
62
|
+
end
|
63
|
+
describe 'when ENV CERBERUS_PASS is set' do
|
64
|
+
let(:app) { AdminWithCerberusPass.new }
|
65
|
+
it 'Has cerberus_active' do
|
66
|
+
assert settings.cerberus_active
|
67
|
+
end
|
68
|
+
end
|
69
|
+
describe 'when ENV CERBERUS_PASS is set but gem not loaded' do
|
70
|
+
let(:app) { AdminCerberusNotAvailable.new }
|
71
|
+
it 'Does not have cerberus_active' do
|
72
|
+
refute settings.cerberus_active
|
73
|
+
end
|
74
|
+
end
|
75
|
+
describe 'when ENV CERBERUS_PASS is set but cerberus is disabled' do
|
76
|
+
let(:app) { AdminCerberusDisabled.new }
|
77
|
+
it 'Does not have cerberus_active' do
|
78
|
+
refute settings.cerberus_active
|
79
|
+
end
|
80
|
+
end
|
81
|
+
describe 'when Cerberus is active' do
|
82
|
+
let(:app) { AdminWithCerberusPass.new }
|
83
|
+
it 'Sets logout_path to /logout' do
|
84
|
+
assert_equal '/logout', settings.logout_path
|
85
|
+
end
|
86
|
+
end
|
87
|
+
describe 'when Cerberus is not active' do
|
88
|
+
it 'Sets logout_path to false' do
|
89
|
+
refute settings.logout_path
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe 'Middlewares' do
|
95
|
+
|
96
|
+
it 'Has API middleware mounted on /api' do
|
97
|
+
get '/api'
|
98
|
+
assert_predicate last_response, :ok?
|
99
|
+
assert_json last_response
|
100
|
+
assert json['success']
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'Has assets available on /__assets__' do
|
104
|
+
get('/__assets__/css/main.css')
|
105
|
+
assert_predicate last_response, :ok?
|
106
|
+
assert_equal 'text/css', last_response.content_type
|
107
|
+
end
|
108
|
+
|
109
|
+
describe 'when cerberus is active' do
|
110
|
+
let(:app) { AdminWithCerberusPass.new }
|
111
|
+
it 'Uses Cerberus for authentication' do
|
112
|
+
get '/'
|
113
|
+
assert_equal 401, last_response.status
|
114
|
+
end
|
115
|
+
end
|
116
|
+
describe 'when cerberus is inactive' do
|
117
|
+
it 'Does not use Cerberus' do
|
118
|
+
get '/'
|
119
|
+
assert_predicate last_response, :ok?
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
describe 'Handlers' do
|
126
|
+
|
127
|
+
let(:help_item) {
|
128
|
+
{ 'title' => '?', 'href' => '/help', 'new_page' => false }
|
129
|
+
}
|
130
|
+
|
131
|
+
describe '/menu' do
|
132
|
+
|
133
|
+
describe 'when url is root' do
|
134
|
+
it 'Returns the correct info' do
|
135
|
+
get '/menu'
|
136
|
+
assert_predicate last_response, :ok?
|
137
|
+
assert_json last_response
|
138
|
+
assert_for_view json, 'template_menu', 'Menu'
|
139
|
+
expected_h = {
|
140
|
+
'title' => 'Home Details',
|
141
|
+
'href' => '/admin/form/home-details/0',
|
142
|
+
'new_page' => false
|
143
|
+
}
|
144
|
+
assert_equal expected_h, json['items'][0]
|
145
|
+
expected_h = {
|
146
|
+
'title' => 'Project Page',
|
147
|
+
'href' => '/menu/project-page',
|
148
|
+
'new_page' => false
|
149
|
+
}
|
150
|
+
assert_equal expected_h, json['items'][1]
|
151
|
+
end
|
152
|
+
it 'Adds help link' do
|
153
|
+
get '/menu'
|
154
|
+
assert_equal 3, json['items'].size
|
155
|
+
assert_equal(help_item, json['items'].last)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
describe 'when url is nested' do
|
159
|
+
it 'Returns the correct info' do
|
160
|
+
get '/menu/project-page/checks'
|
161
|
+
assert_predicate last_response, :ok?
|
162
|
+
assert_json last_response
|
163
|
+
assert_for_view json, 'template_menu', 'Checks'
|
164
|
+
assert_equal 2, json['items'].size
|
165
|
+
expected_h = {
|
166
|
+
'title' => 'Check 1',
|
167
|
+
'href' => '/check/1',
|
168
|
+
'new_page' => false
|
169
|
+
}
|
170
|
+
assert_equal expected_h, json['items'][0]
|
171
|
+
end
|
172
|
+
it 'Does not add help link' do
|
173
|
+
get '/menu/project-page/checks'
|
174
|
+
refute_equal(help_item, json['items'].last)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
data/test/test_api.rb
ADDED
@@ -0,0 +1,246 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
require 'populate_me/document'
|
4
|
+
class Band < PopulateMe::Document
|
5
|
+
attr_accessor :name, :awsome, :position
|
6
|
+
def members; @members ||= []; end
|
7
|
+
def validate
|
8
|
+
error_on(:name,"WTF") if self.name=='ZZ Top'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
class Band::Member < PopulateMe::Document
|
12
|
+
attr_accessor :name
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'populate_me/api'
|
16
|
+
|
17
|
+
describe 'PopulateMe::API' do
|
18
|
+
|
19
|
+
# This middleware has the CRUD interface for
|
20
|
+
# managing documents through a JSON-based API
|
21
|
+
#
|
22
|
+
# The API needs the Document class to implement these methods:
|
23
|
+
# - Class.admin_get
|
24
|
+
# - Needs to be able to accept the ID as a string
|
25
|
+
# - The class is responsible for conversion
|
26
|
+
# - So a mix of different classes of IDs is not possible
|
27
|
+
# - instance.to_h
|
28
|
+
# - instance.save
|
29
|
+
# - instance.delete
|
30
|
+
|
31
|
+
parallelize_me!
|
32
|
+
|
33
|
+
let(:app) {
|
34
|
+
PopulateMe::API.new
|
35
|
+
}
|
36
|
+
|
37
|
+
let(:json) {
|
38
|
+
JSON.parse(last_response.body)
|
39
|
+
}
|
40
|
+
|
41
|
+
def assert_not_found
|
42
|
+
assert_json last_response
|
43
|
+
assert_equal 404, last_response.status
|
44
|
+
assert_equal 'pass', last_response.headers['X-Cascade']
|
45
|
+
refute json['success']
|
46
|
+
assert_equal 'Not Found', json['message']
|
47
|
+
end
|
48
|
+
|
49
|
+
def assert_successful_creation
|
50
|
+
assert_json last_response
|
51
|
+
assert_equal 201, last_response.status
|
52
|
+
assert json['success']
|
53
|
+
assert_equal 'Created Successfully', json['message']
|
54
|
+
end
|
55
|
+
|
56
|
+
def assert_successful_sorting
|
57
|
+
assert_json last_response
|
58
|
+
assert_predicate last_response, :ok?
|
59
|
+
assert json['success']
|
60
|
+
assert_equal 'Sorted Successfully', json['message']
|
61
|
+
end
|
62
|
+
|
63
|
+
def assert_invalid_instance
|
64
|
+
assert_json last_response
|
65
|
+
assert_equal 400, last_response.status
|
66
|
+
refute json['success']
|
67
|
+
assert_equal 'Invalid Document', json['message']
|
68
|
+
end
|
69
|
+
|
70
|
+
def assert_successful_instance
|
71
|
+
assert_json last_response
|
72
|
+
assert_predicate last_response, :ok?
|
73
|
+
assert json['success']
|
74
|
+
end
|
75
|
+
|
76
|
+
def assert_successful_update
|
77
|
+
assert_json last_response
|
78
|
+
assert_predicate last_response, :ok?
|
79
|
+
assert json['success']
|
80
|
+
assert_equal 'Updated Successfully', json['message']
|
81
|
+
end
|
82
|
+
|
83
|
+
def assert_successful_deletion
|
84
|
+
assert_json last_response
|
85
|
+
assert_predicate last_response, :ok?
|
86
|
+
assert json['success']
|
87
|
+
assert_equal 'Deleted Successfully', json['message']
|
88
|
+
end
|
89
|
+
|
90
|
+
describe 'GET /version' do
|
91
|
+
it 'Returns the PopulateMe version' do
|
92
|
+
get('/version')
|
93
|
+
assert_json last_response
|
94
|
+
assert_predicate last_response, :ok?
|
95
|
+
assert json['success']
|
96
|
+
assert_equal PopulateMe::VERSION, json['version']
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe 'POST /:model' do
|
101
|
+
|
102
|
+
it 'Creates successfully' do
|
103
|
+
post('/band', {data: {id: 'neurosis', name: 'Neurosis'}})
|
104
|
+
assert_successful_creation
|
105
|
+
assert_equal 'Neurosis', json['data']['name']
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'Typecasts before creating' do
|
109
|
+
post('/band', {data: {name: 'Arcade Fire', awsome: 'true'}})
|
110
|
+
assert_successful_creation
|
111
|
+
assert json['data']['awsome']
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'Can create a doc even if no data is sent' do
|
115
|
+
post '/band'
|
116
|
+
assert_successful_creation
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'Fails if the doc is invalid' do
|
120
|
+
post('/band', {data: {id: 'invalid_doc_post', name: 'ZZ Top'}})
|
121
|
+
assert_invalid_instance
|
122
|
+
assert_equal({'name'=>['WTF']}, json['data'])
|
123
|
+
assert_nil Band.admin_get('invalid_doc_post')
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'Redirects if destination is given' do
|
127
|
+
post '/band', {'_destination'=>'http://example.org/anywhere'}
|
128
|
+
assert_equal 302, last_response.status
|
129
|
+
assert_equal 'http://example.org/anywhere', last_response.header['Location']
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
describe 'PUT /:model' do
|
135
|
+
|
136
|
+
it 'Can set indexes for sorting' do
|
137
|
+
post('/band', {data: {id: 'sortable1', name: 'Sortable 1'}})
|
138
|
+
post('/band', {data: {id: 'sortable2', name: 'Sortable 2'}})
|
139
|
+
post('/band', {data: {id: 'sortable3', name: 'Sortable 3'}})
|
140
|
+
put '/band', {
|
141
|
+
'action'=>'sort',
|
142
|
+
'field'=>'position',
|
143
|
+
'ids'=> ['sortable2','sortable3','sortable1']
|
144
|
+
}
|
145
|
+
assert_successful_sorting
|
146
|
+
assert_equal 0, Band.admin_get('sortable2').position
|
147
|
+
assert_equal 1, Band.admin_get('sortable3').position
|
148
|
+
assert_equal 2, Band.admin_get('sortable1').position
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'Redirects after sorting if destination is given' do
|
152
|
+
post('/band', {data: {id: 'redirectsortable1', name: 'Redirect Sortable 1'}})
|
153
|
+
post('/band', {data: {id: 'redirectsortable2', name: 'Redirect Sortable 2'}})
|
154
|
+
post('/band', {data: {id: 'redirectsortable3', name: 'Redirect Sortable 3'}})
|
155
|
+
put '/band', {
|
156
|
+
'action'=>'sort',
|
157
|
+
'field'=>'position',
|
158
|
+
'ids'=> ['redirectsortable2','redirectsortable3','redirectsortable1'],
|
159
|
+
'_destination'=>'http://example.org/anywhere'
|
160
|
+
}
|
161
|
+
assert_equal 302, last_response.status
|
162
|
+
assert_equal 'http://example.org/anywhere', last_response.header['Location']
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
describe 'GET /:model/:id' do
|
168
|
+
it 'Sends a not-found when the model is not a class' do
|
169
|
+
get('/wizz/42')
|
170
|
+
assert_not_found
|
171
|
+
end
|
172
|
+
it 'Sends not-found when the model is a class but not a model' do
|
173
|
+
get('/string/42')
|
174
|
+
assert_not_found
|
175
|
+
end
|
176
|
+
it 'Sends not-found when the id is not provided' do
|
177
|
+
get('/band/')
|
178
|
+
assert_not_found
|
179
|
+
end
|
180
|
+
it 'Sends not-found when the instance does not exist' do
|
181
|
+
get('/band/666')
|
182
|
+
assert_not_found
|
183
|
+
end
|
184
|
+
it 'Sends the instance if it exists' do
|
185
|
+
post('/band', {data: {id: 'sendable', name: 'Morphine'}})
|
186
|
+
get('/band/sendable')
|
187
|
+
assert_successful_instance
|
188
|
+
assert_equal Band.admin_get('sendable').to_h, json['data']
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe 'PUT /:model/:id' do
|
193
|
+
it 'Sends not-found if the instance does not exist' do
|
194
|
+
put('/band/666')
|
195
|
+
assert_not_found
|
196
|
+
end
|
197
|
+
it 'Fails if the document is invalid' do
|
198
|
+
post('/band', {data: {id: 'invalid_doc_put', name: 'Valid here'}})
|
199
|
+
put('/band/invalid_doc_put', {data: {name: 'ZZ Top'}})
|
200
|
+
assert_invalid_instance
|
201
|
+
assert_equal({'name'=>['WTF']}, json['data'])
|
202
|
+
refute_equal 'ZZ Top', Band.admin_get('invalid_doc_put').name
|
203
|
+
end
|
204
|
+
it 'Updates documents' do
|
205
|
+
post('/band', {data: {id: 'updatable', name: 'Updatable'}})
|
206
|
+
put('/band/updatable', {data: {awsome: 'yes'}})
|
207
|
+
assert_successful_update
|
208
|
+
obj = Band.admin_get('updatable')
|
209
|
+
assert_equal 'yes', obj.awsome
|
210
|
+
assert_equal 'Updatable', obj.name
|
211
|
+
end
|
212
|
+
# it 'Updates nested documents' do
|
213
|
+
# obj = Band.admin_get('3')
|
214
|
+
# put('/band/3', {data: {members: [
|
215
|
+
# {id: obj.members[0].id, _class: 'Band::Member', name: 'Joey Ramone'},
|
216
|
+
# {id: obj.members[1].id, _class: 'Band::Member'},
|
217
|
+
# ]}})
|
218
|
+
# assert_successful_update
|
219
|
+
# obj = Band.admin_get('3')
|
220
|
+
# assert_equal 'yes', obj.awsome
|
221
|
+
# assert_equal 'The Ramones', obj.name
|
222
|
+
# assert_equal 2, obj.members.size
|
223
|
+
# assert_equal 'Joey Ramone', obj.members[0].name
|
224
|
+
# assert_equal 'Deedee Ramone', obj.members[1].name
|
225
|
+
# end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe 'DELETE /:model/:id' do
|
229
|
+
it 'Sends not-found if the instance does not exist' do
|
230
|
+
delete('/band/666')
|
231
|
+
assert_not_found
|
232
|
+
end
|
233
|
+
it 'Returns a deletion response when the instance exists' do
|
234
|
+
post('/band', {data: {id: 'deletable', name: '1D'}})
|
235
|
+
delete('/band/deletable')
|
236
|
+
assert_successful_deletion
|
237
|
+
assert_instance_of Hash, json['data']
|
238
|
+
end
|
239
|
+
it 'Redirects if destination is given' do
|
240
|
+
delete('/band/2', {'_destination'=>'http://example.org/anywhere'})
|
241
|
+
assert_equal 302, last_response.status
|
242
|
+
assert_equal 'http://example.org/anywhere', last_response.header['Location']
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|