vault-rails 0.0.11 → 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 (48) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +362 -0
  3. data/README.md +106 -0
  4. data/Rakefile +18 -2
  5. data/lib/vault/encrypted_model.rb +112 -0
  6. data/lib/vault/rails.rb +30 -0
  7. data/lib/vault/rails/version.rb +1 -1
  8. data/spec/dummy/Rakefile +6 -0
  9. data/spec/dummy/app/models/person.rb +8 -0
  10. data/spec/dummy/bin/bundle +3 -0
  11. data/spec/dummy/bin/rails +4 -0
  12. data/spec/dummy/bin/rake +4 -0
  13. data/spec/dummy/config.ru +4 -0
  14. data/spec/dummy/config/application.rb +29 -0
  15. data/spec/dummy/config/boot.rb +5 -0
  16. data/spec/dummy/config/database.yml +12 -0
  17. data/spec/dummy/config/environment.rb +5 -0
  18. data/spec/dummy/config/environments/development.rb +37 -0
  19. data/spec/dummy/config/environments/test.rb +39 -0
  20. data/spec/dummy/config/initializers/assets.rb +8 -0
  21. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  22. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  23. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  24. data/spec/dummy/config/initializers/inflections.rb +16 -0
  25. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  26. data/spec/dummy/config/initializers/session_store.rb +3 -0
  27. data/spec/dummy/config/initializers/vault.rb +9 -0
  28. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  29. data/spec/dummy/config/locales/en.yml +23 -0
  30. data/spec/dummy/config/routes.rb +3 -0
  31. data/spec/dummy/config/secrets.yml +22 -0
  32. data/spec/dummy/db/development.sqlite3 +0 -0
  33. data/spec/dummy/db/migrate/20150428220101_create_people.rb +11 -0
  34. data/spec/dummy/db/schema.rb +24 -0
  35. data/spec/dummy/log/development.log +124 -0
  36. data/spec/dummy/public/404.html +67 -0
  37. data/spec/dummy/public/422.html +67 -0
  38. data/spec/dummy/public/500.html +66 -0
  39. data/spec/dummy/public/favicon.ico +0 -0
  40. data/spec/integration/rails_spec.rb +27 -0
  41. data/spec/spec_helper.rb +24 -0
  42. data/spec/support/vault_server.rb +68 -0
  43. data/spec/unit/rails_spec.rb +28 -0
  44. metadata +178 -23
  45. data/lib/vault-rails.rb +0 -5
  46. data/lib/vault/rails/engine.rb +0 -8
  47. data/vendor/assets/javascripts/vault.js.coffee +0 -629
  48. data/vendor/assets/javascripts/vault/vault.js.coffee +0 -629
@@ -0,0 +1,68 @@
1
+ require "open-uri"
2
+ require "singleton"
3
+ require "timeout"
4
+ require "tempfile"
5
+
6
+ module RSpec
7
+ class VaultServer
8
+ include Singleton
9
+
10
+ def self.method_missing(m, *args, &block)
11
+ self.instance.public_send(m, *args, &block)
12
+ end
13
+
14
+ attr_reader :token
15
+
16
+ def initialize
17
+ io = Tempfile.new("vault-server")
18
+ pid = Process.spawn({}, "vault server -dev", out: io.to_i, err: io.to_i)
19
+
20
+ at_exit do
21
+ Process.kill("INT", pid)
22
+ Process.waitpid2(pid)
23
+
24
+ io.close
25
+ io.unlink
26
+ end
27
+
28
+ wait_for_ready do
29
+ output = ""
30
+
31
+ while
32
+ io.rewind
33
+ output = io.read
34
+ break if !output.empty?
35
+ end
36
+
37
+ if output.match(/Root Token: (.+)/)
38
+ @token = $1.strip
39
+ else
40
+ raise "Vault did not return a token!"
41
+ end
42
+ end
43
+ end
44
+
45
+ def address
46
+ "http://127.0.0.1:8200"
47
+ end
48
+
49
+ def wait_for_ready(&block)
50
+ Timeout.timeout(5) do
51
+ while
52
+ begin
53
+ open(address)
54
+ rescue SocketError, Errno::ECONNREFUSED, EOFError
55
+ rescue OpenURI::HTTPError => e
56
+ break if e.message =~ /404/
57
+ end
58
+
59
+ sleep(0.25)
60
+ end
61
+ end
62
+
63
+ yield
64
+ rescue Timeout::Error
65
+ raise "Vault did not start in 5 seconds!"
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,28 @@
1
+ require "spec_helper"
2
+
3
+ describe Vault do
4
+ describe ".application" do
5
+ it "returns the application" do
6
+ Vault.instance_variable_set(:@application, "test")
7
+ expect(Vault.application).to eq("test")
8
+ end
9
+
10
+ it "raises an error if unset" do
11
+ Vault.instance_variable_set(:@application, nil)
12
+ expect { Vault.application }.to raise_error
13
+ end
14
+ end
15
+
16
+ describe ".application=" do
17
+ it "sets the value" do
18
+ Vault.application = "test"
19
+ expect(Vault.instance_variable_get(:@application)).to eq("test")
20
+ end
21
+ end
22
+
23
+ describe "Rails" do
24
+ it "is defined" do
25
+ expect { Vault.const_get(:Rails) }.to_not raise_error
26
+ end
27
+ end
28
+ end
metadata CHANGED
@@ -1,51 +1,206 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vault-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.11
5
- prerelease:
4
+ version: 0.1.0
6
5
  platform: ruby
7
6
  authors:
8
- - Jordan MacDonald
7
+ - Seth Vargo
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-01-05 00:00:00.000000000Z
13
- dependencies: []
14
- description: Store and manage collections of objects without a connection.
11
+ date: 2015-05-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: vault
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sqlite3
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Official Vault plugin for Rails
15
98
  email:
16
- - jordan.macdonald@greatersudbury.ca
99
+ - sethvargo@gmail.com
17
100
  executables: []
18
101
  extensions: []
19
102
  extra_rdoc_files: []
20
103
  files:
21
- - lib/vault-rails.rb
22
- - lib/vault/rails/version.rb
23
- - lib/vault/rails/engine.rb
24
- - vendor/assets/javascripts/vault/vault.js.coffee
25
- - vendor/assets/javascripts/vault.js.coffee
104
+ - LICENSE
105
+ - README.md
26
106
  - Rakefile
27
- homepage: https://github.com/cityofgreatersudbury/vault-rails
28
- licenses: []
107
+ - lib/vault/encrypted_model.rb
108
+ - lib/vault/rails.rb
109
+ - lib/vault/rails/version.rb
110
+ - spec/dummy/Rakefile
111
+ - spec/dummy/app/models/person.rb
112
+ - spec/dummy/bin/bundle
113
+ - spec/dummy/bin/rails
114
+ - spec/dummy/bin/rake
115
+ - spec/dummy/config.ru
116
+ - spec/dummy/config/application.rb
117
+ - spec/dummy/config/boot.rb
118
+ - spec/dummy/config/database.yml
119
+ - spec/dummy/config/environment.rb
120
+ - spec/dummy/config/environments/development.rb
121
+ - spec/dummy/config/environments/test.rb
122
+ - spec/dummy/config/initializers/assets.rb
123
+ - spec/dummy/config/initializers/backtrace_silencers.rb
124
+ - spec/dummy/config/initializers/cookies_serializer.rb
125
+ - spec/dummy/config/initializers/filter_parameter_logging.rb
126
+ - spec/dummy/config/initializers/inflections.rb
127
+ - spec/dummy/config/initializers/mime_types.rb
128
+ - spec/dummy/config/initializers/session_store.rb
129
+ - spec/dummy/config/initializers/vault.rb
130
+ - spec/dummy/config/initializers/wrap_parameters.rb
131
+ - spec/dummy/config/locales/en.yml
132
+ - spec/dummy/config/routes.rb
133
+ - spec/dummy/config/secrets.yml
134
+ - spec/dummy/db/development.sqlite3
135
+ - spec/dummy/db/migrate/20150428220101_create_people.rb
136
+ - spec/dummy/db/schema.rb
137
+ - spec/dummy/log/development.log
138
+ - spec/dummy/public/404.html
139
+ - spec/dummy/public/422.html
140
+ - spec/dummy/public/500.html
141
+ - spec/dummy/public/favicon.ico
142
+ - spec/integration/rails_spec.rb
143
+ - spec/spec_helper.rb
144
+ - spec/support/vault_server.rb
145
+ - spec/unit/rails_spec.rb
146
+ homepage: https://github.com/hashicorp/vault-rails
147
+ licenses:
148
+ - MPLv3
149
+ metadata: {}
29
150
  post_install_message:
30
151
  rdoc_options: []
31
152
  require_paths:
32
153
  - lib
33
154
  required_ruby_version: !ruby/object:Gem::Requirement
34
- none: false
35
155
  requirements:
36
- - - ! '>='
156
+ - - ">="
37
157
  - !ruby/object:Gem::Version
38
158
  version: '0'
39
159
  required_rubygems_version: !ruby/object:Gem::Requirement
40
- none: false
41
160
  requirements:
42
- - - ! '>='
161
+ - - ">="
43
162
  - !ruby/object:Gem::Version
44
163
  version: '0'
45
164
  requirements: []
46
- rubyforge_project: vault-rails
47
- rubygems_version: 1.8.10
165
+ rubyforge_project:
166
+ rubygems_version: 2.2.3
48
167
  signing_key:
49
- specification_version: 3
50
- summary: CoffeeScript collection class for offline use.
51
- test_files: []
168
+ specification_version: 4
169
+ summary: Official Vault plugin for Rails
170
+ test_files:
171
+ - spec/dummy/app/models/person.rb
172
+ - spec/dummy/bin/bundle
173
+ - spec/dummy/bin/rails
174
+ - spec/dummy/bin/rake
175
+ - spec/dummy/config/application.rb
176
+ - spec/dummy/config/boot.rb
177
+ - spec/dummy/config/database.yml
178
+ - spec/dummy/config/environment.rb
179
+ - spec/dummy/config/environments/development.rb
180
+ - spec/dummy/config/environments/test.rb
181
+ - spec/dummy/config/initializers/assets.rb
182
+ - spec/dummy/config/initializers/backtrace_silencers.rb
183
+ - spec/dummy/config/initializers/cookies_serializer.rb
184
+ - spec/dummy/config/initializers/filter_parameter_logging.rb
185
+ - spec/dummy/config/initializers/inflections.rb
186
+ - spec/dummy/config/initializers/mime_types.rb
187
+ - spec/dummy/config/initializers/session_store.rb
188
+ - spec/dummy/config/initializers/vault.rb
189
+ - spec/dummy/config/initializers/wrap_parameters.rb
190
+ - spec/dummy/config/locales/en.yml
191
+ - spec/dummy/config/routes.rb
192
+ - spec/dummy/config/secrets.yml
193
+ - spec/dummy/config.ru
194
+ - spec/dummy/db/development.sqlite3
195
+ - spec/dummy/db/migrate/20150428220101_create_people.rb
196
+ - spec/dummy/db/schema.rb
197
+ - spec/dummy/log/development.log
198
+ - spec/dummy/public/404.html
199
+ - spec/dummy/public/422.html
200
+ - spec/dummy/public/500.html
201
+ - spec/dummy/public/favicon.ico
202
+ - spec/dummy/Rakefile
203
+ - spec/integration/rails_spec.rb
204
+ - spec/spec_helper.rb
205
+ - spec/support/vault_server.rb
206
+ - spec/unit/rails_spec.rb
data/lib/vault-rails.rb DELETED
@@ -1,5 +0,0 @@
1
- module Vault
2
- module Rails
3
- require 'vault/rails/engine' if defined?(Rails)
4
- end
5
- end
@@ -1,8 +0,0 @@
1
- require 'rails'
2
-
3
- module Vault
4
- module Rails
5
- class Engine < ::Rails::Engine
6
- end
7
- end
8
- end
@@ -1,629 +0,0 @@
1
- class Vault
2
- constructor: (@name, @urls, options = {}) ->
3
- # Setup some internal variables.
4
- @objects = []
5
- @dirty_object_count = 0
6
- @save_error_count = 0
7
- @messages =
8
- notices: []
9
- warnings: []
10
- errors: []
11
-
12
- # This property is used to temporarily lock the vault during mutation methods.
13
- @locked = false
14
-
15
- # Declare default options.
16
- @options =
17
- autoload: true
18
- after_load: ->
19
- id_attribute: "id"
20
- offline: false
21
- sub_collections: []
22
-
23
- # Declare an array used to track ids that are in use,
24
- # so as to prevent duplicates when generating new ones.
25
- @ids_in_use = []
26
-
27
- # Merge default options with user-defined ones.
28
- for option, value of options
29
- @options[option] = value
30
-
31
- # Setup the vault for offline use.
32
- if @options.offline
33
- # Bind a cache routine to save data should the window be closed or url changed.
34
- $(window).unload =>
35
- @store()
36
-
37
- # Load the collection if configured to do so.
38
- if @options.autoload
39
- # Check the offline data store first, if configured to do so.
40
- if @options.offline
41
- if @load()
42
- if @dirty_object_count > 0
43
- # Offline data loaded and modifications found; keep existing data.
44
- @messages.notices.push "Found and using dirty offline data."
45
-
46
- # Detach the callback to after_load so that the call to the
47
- # vault constructor can complete/return, allowing any post-load code
48
- # to use the newly instantiated vault object as required.
49
- window.setTimeout @options.after_load, 100
50
- else
51
- # No modifications in offline data; reload fresh data.
52
- @messages.notices.push "No modifications found in offline data. Reloading..."
53
-
54
- if @urls.list?
55
- @reload(@options.after_load)
56
- else
57
- # Can't reload without a list url; use the offline data we've loaded.
58
- @messages.notices.push "List url not configured; using offline data instead."
59
-
60
- # Detach the callback to after_load so that the call to the
61
- # vault constructor can complete/return, allowing any post-load code
62
- # to use the newly instantiated vault object as required.
63
- window.setTimeout @options.after_load, 100
64
- else
65
- if navigator.onLine
66
- # Load failed, but we're connected; reload fresh data.
67
- @messages.warnings.push "Offline data load failed. Reloading..."
68
-
69
- if @urls.list?
70
- @reload(@options.after_load)
71
- else
72
- # Can't reload without a list url; use an empty dataset.
73
- @messages.warnings.push "List url not configured; using empty dataset instead."
74
-
75
- # Detach the callback to after_load so that the call to the
76
- # vault constructor can complete/return, allowing any post-load code
77
- # to use the newly instantiated vault object as required.
78
- window.setTimeout @options.after_load, 100
79
- else
80
- # Load failed and we're offline; use an empty dataset.
81
- @messages.warnings.push "Browser is offline and cannot reload; using empty dataset instead."
82
-
83
- # Detach the callback to after_load so that the call to the
84
- # vault constructor can complete/return, allowing any post-load code
85
- # to use the newly instantiated vault object as required.
86
- window.setTimeout @options.after_load, 100
87
- else
88
- # Not using offline data; reload fresh data.
89
- @messages.notices.push "Not configured for offline data. Reloading..."
90
-
91
- if @urls.list?
92
- @reload(@options.after_load)
93
- else
94
- # Can't reload without a list url; use an empty dataset.
95
- @messages.notices.push "List url not configured; using empty dataset instead."
96
-
97
- # Detach the callback to after_load so that the call to the
98
- # vault constructor can complete/return, allowing any post-load code
99
- # to use the newly instantiated vault object as required.
100
- window.setTimeout @options.after_load, 100
101
-
102
- # Create convenience attributes for sub-collections.
103
- for sub_collection in @options.sub_collections
104
- do (sub_collection) =>
105
- @[sub_collection] = {
106
- 'find': (id) =>
107
- for object in @objects
108
- for sub_object in object[sub_collection]
109
- if sub_object[@options.id_attribute].toString() is id.toString()
110
- return sub_object
111
-
112
- # Object with specified id couldn't be found.
113
- return false
114
- }
115
-
116
- # Iterate over non-deleted items in the collection.
117
- each: (logic) ->
118
- for object in @objects
119
- unless object.status == "deleted"
120
- logic object
121
-
122
- # Add a new item to the collection.
123
- add: (object) ->
124
- # Don't bother if the vault is locked.
125
- if @locked
126
- @messages.errors.push 'Cannot add, vault is locked.'
127
- return false
128
-
129
- # If the object has no id, generate a temporary one and add it to the object.
130
- unless object[@options.id_attribute]? and object[@options.id_attribute] isnt ''
131
- object[@options.id_attribute] = @generate_id()
132
-
133
- # Extend the object with vault-specific variables and functions.
134
- @extend object,"new"
135
-
136
- # Add the object to the collection.
137
- @objects.push object
138
-
139
- # Increase the count of dirty objects.
140
- @dirty_object_count++
141
-
142
- # Store the collection.
143
- @store
144
-
145
- # Return the extended object.
146
- return object
147
-
148
- # Find an object in the collection using its id.
149
- find: (id) ->
150
- for object in @objects
151
- if object[@options.id_attribute].toString() is id.toString()
152
- return object
153
-
154
- # Object with specified id couldn't be found.
155
- return false
156
-
157
- # Update an existing item in the collection.
158
- update: (attributes, id) ->
159
- # Don't bother if the vault is locked.
160
- if @locked
161
- @messages.errors.push 'Cannot update, vault is locked.'
162
- return false
163
-
164
- # Get the id of the object from the attributes if it's not explicitly defined.
165
- id = attributes[@options.id_attribute] unless id?
166
-
167
- # Get the object; return if it's undefined.
168
- object = @find(id)
169
- unless object?
170
- @messages.errors.push 'Cannot update, object not found.'
171
- return false
172
-
173
- # Flag it as dirty.
174
- if object.status is "clean"
175
- object.status = "dirty"
176
- @dirty_object_count++
177
-
178
- # Merge in the updated attributes, if they're specified and defined on the object.
179
- if attributes?
180
- for attribute, value of attributes
181
- if object[attribute]?
182
- object[attribute] = value
183
-
184
- # Store the collection.
185
- @store
186
-
187
- # Update was successful.
188
- return true
189
-
190
- # Flag an object in the collection for deletion,
191
- # or if the object is new, remove it.
192
- delete: (id) ->
193
- # Don't bother if the vault is locked.
194
- if @locked
195
- @messages.errors.push 'Cannot delete, vault is locked.'
196
- return false
197
-
198
- for object, index in @objects
199
- if object[@options.id_attribute] == id
200
- switch object.status
201
- when "new"
202
- # New objects are special; we essentially want to
203
- # reverse the steps taken during the add operation.
204
- @objects.splice(index, 1)
205
- @dirty_object_count--
206
- when "clean"
207
- object.status = "deleted"
208
- @dirty_object_count++
209
- when "dirty"
210
- object.status = "deleted"
211
-
212
- # Store the collection.
213
- @store
214
-
215
- # Delete was successful.
216
- return true
217
-
218
- # Object not found.
219
- return false
220
-
221
- # Forcibly remove an object from the collection.
222
- destroy: (id) ->
223
- # Don't bother if the vault is locked.
224
- if @locked
225
- @messages.errors.push 'Cannot delete, vault is locked.'
226
- return false
227
-
228
- for object, index in @objects
229
- if object[@options.id_attribute] == id
230
- # Remove the object from the collection.
231
- @objects.splice(index, 1)
232
-
233
- # Reduce the dirty count if this object
234
- # was dirty, since we're no longer managing it.
235
- switch object.status
236
- when "new", "dirty"
237
- @dirty_object_count--
238
-
239
- # Store the collection.
240
- @store
241
-
242
- # Destroy was successful.
243
- return true
244
-
245
- # Object not found.
246
- return false
247
-
248
- # Write an object back to the server.
249
- save: (id, after_save = ->) ->
250
- # Don't bother if the vault is locked, we're offline or there's nothing to sync.
251
- if @locked
252
- @messages.errors.push 'Cannot save, vault is locked.'
253
- return after_save()
254
- else if not navigator.onLine
255
- @messages.errors.push 'Cannot save, navigator is offline.'
256
- return after_save()
257
- else if @dirty_object_count is 0
258
- @messages.errors.push 'Nothing to save.'
259
- return after_save()
260
-
261
- # Lock the vault until the save is complete.
262
- @locked = true
263
-
264
- # Find the object using the specified id.
265
- object = @find(id)
266
-
267
- # Package up the object to be sent to the server.
268
- packaged_object = {}
269
- packaged_object[@name] = JSON.stringify @strip object
270
-
271
- switch object.status
272
- when "deleted"
273
- $.ajax
274
- type: 'DELETE'
275
- url: @urls.delete
276
- data: packaged_object
277
- fixture: (settings) ->
278
- return true
279
- success: (data) =>
280
- # Forcibly remove the deleted object from the collection.
281
- for vault_object, index in @objects
282
- if vault_object.id == object.id
283
- @objects.splice(index, 1)
284
- @dirty_object_count--
285
- error: =>
286
- @messages.errors.push 'Failed to delete.'
287
- complete: =>
288
- # Store the collection, unlock the vault, and execute the callback method.
289
- @store
290
- @locked = false
291
- after_save()
292
- dataType: 'json'
293
- when "new"
294
- $.ajax
295
- type: 'POST'
296
- url: @urls.create
297
- data: packaged_object
298
- fixture: (settings) =>
299
- return {
300
- id: 123
301
- make: "Dodge",
302
- model: "Viper SRT-10",
303
- year: 2008}
304
- success: (data) =>
305
- # Unlock the vault prematurely so that we can update it.
306
- @locked = false
307
-
308
- # Update the object with the attributes sent from the server.
309
- object.update data, object.id
310
-
311
- object.status = "clean"
312
- @dirty_object_count--
313
- error: =>
314
- @messages.errors.push 'Failed to create.'
315
- complete: =>
316
- # Store the collection, unlock the vault, and execute the callback method.
317
- @store
318
- @locked = false
319
- after_save()
320
- dataType: 'json'
321
- when "dirty"
322
- $.ajax
323
- type: 'POST'
324
- url: @urls.update
325
- data: packaged_object
326
- fixture: (settings) ->
327
- return true
328
- success: (data) =>
329
- object.status = "clean"
330
- @dirty_object_count--
331
- error: =>
332
- @messages.errors.push 'Failed to update.'
333
- complete: =>
334
- # Store the collection, unlock the vault, and execute the callback method.
335
- @store
336
- @locked = false
337
- after_save()
338
- dataType: 'json'
339
-
340
- # Used to wipe out the in-memory object list with a fresh one from the server.
341
- reload: (after_load = ->) ->
342
- # Don't bother if the vault is locked or we're offline.
343
- if @locked
344
- @messages.errors.push 'Cannot reload, vault is locked.'
345
- return after_load()
346
- else if not navigator.onLine
347
- @messages.errors.push 'Cannot reload, navigator is offline.'
348
- return after_load()
349
- else if not @urls.list?
350
- @messages.errors.push 'Cannot reload, list url is not configured.'
351
- return after_load()
352
-
353
- # Lock the vault until the reload is complete.
354
- @locked = true
355
-
356
- $.ajax
357
- url: @urls.list
358
- dataType: 'json'
359
- success: (data) =>
360
- # Replace the list of in-memory objects with the new data.
361
- @objects = data
362
-
363
- # Extend the objects with vault-specific variables and functions.
364
- for object in @objects
365
- @extend object
366
-
367
- # Reset the count of dirty objects.
368
- @dirty_object_count = 0
369
-
370
- # Store the collection.
371
- @store
372
-
373
- # Call the callback function as the reload is complete.
374
- after_load()
375
- error: =>
376
- @messages.errors.push 'Failed to list.'
377
-
378
- # Call the callback function as the reload is complete (albeit unsuccessful).
379
- after_load()
380
- complete: =>
381
- # Unlock the vault as the reload is complete.
382
- @locked = false
383
-
384
- # Convenience method for saving and reloading in one shot.
385
- synchronize: (after_sync = ->) ->
386
- # Don't bother if we're offline.
387
- unless navigator.onLine
388
- @messages.errors.push 'Cannot synchronize, navigator is offline.'
389
- return after_sync()
390
-
391
- @save =>
392
- # Only reload the collection if there were no save errors.
393
- if @messages.errors.length is 0
394
- @reload(after_sync)
395
- else
396
- after_sync()
397
-
398
- # Load the collection from offline storage.
399
- load: ->
400
- # Don't bother if offline support is disabled.
401
- unless @options.offline
402
- return false
403
-
404
- # Try to load the collection.
405
- if localStorage.getItem(@name)
406
- @objects = $.parseJSON(localStorage.getItem @name)
407
-
408
- # Extend the loaded objects with vault-specific variables and functions.
409
- for object in @objects
410
- @extend object
411
-
412
- # Calculate the number of dirty objects.
413
- for object in @objects
414
- unless object.status is "clean"
415
- @dirty_object_count++
416
-
417
- return true
418
- else
419
- return false
420
-
421
- # Store the collection for offline use.
422
- store: ->
423
- # Don't bother if offline support is disabled.
424
- unless @options.offline
425
- return false
426
-
427
- # Store the collection.
428
- localStorage.setItem(@name, JSON.stringify(@objects))
429
- return true
430
-
431
- # Extend an object with vault-specific variables and functions.
432
- extend: (object, status) ->
433
- # Validate the status argument.
434
- if status?
435
- throw "Invalid status specified: cannot extend object." unless status in ['clean', 'dirty', 'new']
436
-
437
- # Add simple variables and methods.
438
- object.update = (attributes) =>
439
- @update(attributes, object.id)
440
- object.delete = =>
441
- @delete(object.id)
442
- object.destroy = =>
443
- @destroy(object.id)
444
- object.save = (after_save) =>
445
- @save(object.id, after_save)
446
-
447
- if status?
448
- # Status has been explicitly defined; force it on the object.
449
- object.status = status
450
- else
451
- # Default the object's status to clean if it doesn't exist.
452
- object.status = "clean" unless object.status?
453
-
454
- # Iterate through all of the sub-collections, and if present
455
- # extend them with some basic functionality.
456
- for sub_collection in @options.sub_collections
457
- do (sub_collection) =>
458
- if object[sub_collection]?
459
- # Find functionality.
460
- object[sub_collection].find = (id) =>
461
- for sub_collection_object in object[sub_collection]
462
- if sub_collection_object[@options.id_attribute].toString() is id.toString()
463
- return sub_collection_object
464
-
465
- # Object with specified id couldn't be found.
466
- return false
467
-
468
- # Add functionality.
469
- object[sub_collection].add = (sub_object) =>
470
- # Don't bother if the vault is locked.
471
- if @locked
472
- @messages.errors.push 'Cannot add sub-object, vault is locked.'
473
- return false
474
-
475
- # Set a status on the object.
476
- sub_object.status = "new"
477
-
478
- # If the sub-object has no id, generate a temporary one and add it to the sub-object.
479
- unless sub_object[@options.id_attribute]? and sub_object[@options.id_attribute] isnt ''
480
- sub_object[@options.id_attribute] = @generate_id()
481
-
482
- # Add a delete method to the sub-object.
483
- sub_object.delete = =>
484
- object[sub_collection].delete(sub_object[@options.id_attribute])
485
-
486
- # Add an update method to the sub-object.
487
- sub_object.update = (attributes) =>
488
- object[sub_collection].update(attributes, sub_object[@options.id_attribute])
489
-
490
- # Add the object to the collection.
491
- object[sub_collection].push sub_object
492
-
493
- # If the root object was clean, flag it and increase the count of dirty objects.
494
- if object.status is "clean"
495
- object.status = "dirty"
496
- @dirty_object_count++
497
-
498
- # Store the collection.
499
- @store
500
-
501
- return sub_object
502
-
503
- # Delete functionality.
504
- object[sub_collection].delete = (id) =>
505
- # Don't bother if the vault is locked.
506
- if @locked
507
- @messages.errors.push 'Cannot delete sub-object, vault is locked.'
508
- return false
509
-
510
- # Remove the sub-object from its collection.
511
- for sub_object, index in object[sub_collection]
512
- if sub_object[@options.id_attribute] is id
513
- object[sub_collection].splice(index, 1)
514
-
515
- # If the root object was clean, flag it and increase the count of dirty objects.
516
- if object.status is "clean"
517
- object.status = "dirty"
518
- @dirty_object_count++
519
-
520
- # Store the collection.
521
- @store
522
-
523
- # Add a delete instance method for pre-existing objects.
524
- for sub_object, index in object[sub_collection]
525
- sub_object.delete = =>
526
- object[sub_collection].delete(sub_object[@options.id_attribute])
527
-
528
- # Update functionality.
529
- object[sub_collection].update = (attributes, id) =>
530
- # Don't bother if the vault is locked.
531
- if @locked
532
- @messages.errors.push 'Cannot update sub-object, vault is locked.'
533
- return false
534
-
535
- # Get the id of the sub-object from the attributes if it's not explicitly defined.
536
- id = attributes[@options.id_attribute] unless id?
537
-
538
- # Get the sub-object; return if it's undefined.
539
- sub_object = object[sub_collection].find(id)
540
- unless sub_object?
541
- @messages.errors.push 'Cannot update, sub-object not found.'
542
- return false
543
-
544
- # If the root object was clean, flag it and increase the count of dirty objects.
545
- if object.status is "clean"
546
- object.status = "dirty"
547
- @dirty_object_count++
548
-
549
- # Merge in the updated attributes, if they're specified and defined on the sub-object.
550
- if attributes?
551
- for attribute, value of attributes
552
- if sub_object[attribute]?
553
- sub_object[attribute] = value
554
-
555
- # Store the collection.
556
- @store
557
-
558
- # Add an update instance method for pre-existing objects.
559
- for sub_object in object[sub_collection]
560
- do (sub_object) =>
561
- sub_object.update = (attributes) =>
562
- object[sub_collection].update(attributes, sub_object[@options.id_attribute])
563
-
564
- return object
565
-
566
- # Return a copy of an object with vault-specific variables and functions removed.
567
- strip: (object) ->
568
- # Clone the object so that we don't strip the original.
569
- object_clone = @clone object
570
-
571
- # Remove the temporary id given to new objects.
572
- if object_clone.status is "new"
573
- delete object_clone[@options.id_attribute]
574
-
575
- # Remove vault object methods.
576
- delete object_clone.status
577
- delete object_clone.update
578
- delete object_clone.delete
579
- delete object_clone.destroy
580
- delete object_clone.save
581
-
582
- # Iterate through all of the sub-collections, and if present
583
- # strip them of their extended functionality.
584
- for sub_collection in @options.sub_collections
585
- if object_clone[sub_collection]?
586
- # Remove the sub-collection's methods.
587
- delete object_clone[sub_collection].find
588
- delete object_clone[sub_collection].add
589
- delete object_clone[sub_collection].delete
590
- delete object_clone[sub_collection].update
591
-
592
- # Iterate through and remove the extended instances' methods.
593
- for sub_object in object_clone[sub_collection]
594
- if sub_object.status is "new"
595
- delete sub_object[@options.id_attribute]
596
- delete sub_object.status
597
- delete sub_object.delete
598
- delete sub_object.update
599
- return object_clone
600
-
601
- # Clone (deep copy) an object.
602
- clone: (object) ->
603
- unless object? and typeof object is 'object'
604
- return object
605
-
606
- new_instance = new object.constructor()
607
-
608
- for key of object
609
- new_instance[key] = @clone object[key]
610
-
611
- return new_instance
612
-
613
- # Generate a new unique (within the set of generated ids) id.
614
- generate_id: ->
615
- until id_is_available
616
- # Generate a new id and assume it's available.
617
- id = new Date().getTime()
618
- id_is_available = true
619
-
620
- # Flag the new id as unavailable if it's taken.
621
- id_is_available = false for taken in @ids_in_use when id is taken
622
-
623
- # Store the new id so that it's not used again.
624
- @ids_in_use.push id
625
-
626
- return id
627
-
628
- # Attach the Vault class to the window so that it can be used by other scripts.
629
- window.Vault = this