vault-rails 0.0.11 → 0.1.0

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