vines-services 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/LICENSE +19 -0
  2. data/README +40 -0
  3. data/Rakefile +130 -0
  4. data/bin/vines-services +95 -0
  5. data/conf/config.rb +25 -0
  6. data/lib/vines/services/command/init.rb +209 -0
  7. data/lib/vines/services/command/restart.rb +14 -0
  8. data/lib/vines/services/command/start.rb +30 -0
  9. data/lib/vines/services/command/stop.rb +20 -0
  10. data/lib/vines/services/command/views.rb +26 -0
  11. data/lib/vines/services/component.rb +26 -0
  12. data/lib/vines/services/config.rb +105 -0
  13. data/lib/vines/services/connection.rb +120 -0
  14. data/lib/vines/services/controller/attributes_controller.rb +19 -0
  15. data/lib/vines/services/controller/base_controller.rb +99 -0
  16. data/lib/vines/services/controller/disco_info_controller.rb +61 -0
  17. data/lib/vines/services/controller/labels_controller.rb +17 -0
  18. data/lib/vines/services/controller/members_controller.rb +44 -0
  19. data/lib/vines/services/controller/messages_controller.rb +66 -0
  20. data/lib/vines/services/controller/probes_controller.rb +45 -0
  21. data/lib/vines/services/controller/services_controller.rb +81 -0
  22. data/lib/vines/services/controller/subscriptions_controller.rb +39 -0
  23. data/lib/vines/services/controller/systems_controller.rb +45 -0
  24. data/lib/vines/services/controller/transfers_controller.rb +58 -0
  25. data/lib/vines/services/controller/uploads_controller.rb +62 -0
  26. data/lib/vines/services/controller/users_controller.rb +127 -0
  27. data/lib/vines/services/core_ext/blather.rb +46 -0
  28. data/lib/vines/services/core_ext/couchrest.rb +33 -0
  29. data/lib/vines/services/indexer.rb +195 -0
  30. data/lib/vines/services/priority_queue.rb +94 -0
  31. data/lib/vines/services/roster.rb +70 -0
  32. data/lib/vines/services/storage/couchdb/fragment.rb +23 -0
  33. data/lib/vines/services/storage/couchdb/service.rb +170 -0
  34. data/lib/vines/services/storage/couchdb/system.rb +141 -0
  35. data/lib/vines/services/storage/couchdb/upload.rb +66 -0
  36. data/lib/vines/services/storage/couchdb/user.rb +137 -0
  37. data/lib/vines/services/storage/couchdb/vcard.rb +13 -0
  38. data/lib/vines/services/storage/couchdb.rb +157 -0
  39. data/lib/vines/services/storage.rb +33 -0
  40. data/lib/vines/services/throttle.rb +26 -0
  41. data/lib/vines/services/version.rb +7 -0
  42. data/lib/vines/services/vql/compiler.rb +94 -0
  43. data/lib/vines/services/vql/vql.citrus +115 -0
  44. data/lib/vines/services/vql/vql.rb +186 -0
  45. data/lib/vines/services.rb +71 -0
  46. data/test/config_test.rb +242 -0
  47. data/test/priority_queue_test.rb +23 -0
  48. data/test/storage/couchdb_test.rb +30 -0
  49. data/test/vql/compiler_test.rb +96 -0
  50. data/test/vql/vql_test.rb +233 -0
  51. data/web/coffeescripts/api.coffee +51 -0
  52. data/web/coffeescripts/commands.coffee +18 -0
  53. data/web/coffeescripts/files.coffee +315 -0
  54. data/web/coffeescripts/init.coffee +21 -0
  55. data/web/coffeescripts/services.coffee +356 -0
  56. data/web/coffeescripts/setup.coffee +503 -0
  57. data/web/coffeescripts/systems.coffee +371 -0
  58. data/web/images/default-service.png +0 -0
  59. data/web/images/linux.png +0 -0
  60. data/web/images/mac.png +0 -0
  61. data/web/images/run.png +0 -0
  62. data/web/images/windows.png +0 -0
  63. data/web/index.html +17 -0
  64. data/web/stylesheets/common.css +52 -0
  65. data/web/stylesheets/files.css +218 -0
  66. data/web/stylesheets/services.css +181 -0
  67. data/web/stylesheets/setup.css +117 -0
  68. data/web/stylesheets/systems.css +142 -0
  69. metadata +230 -0
@@ -0,0 +1,503 @@
1
+ class SetupPage
2
+ SERVICES = 'http://getvines.com/protocol/services'
3
+ SYSTEMS = 'http://getvines.com/protocol/systems'
4
+ USERS = 'http://getvines.com/protocol/users'
5
+
6
+ constructor: (@session) ->
7
+ @api = new Api @session
8
+ @layout = null
9
+ @selected = null
10
+ @services = []
11
+ @users = []
12
+
13
+ findSystem: (name) ->
14
+ @api.get SYSTEMS, {name: name}, (result) =>
15
+ this.drawSystemInfo(result)
16
+
17
+ findServices: ->
18
+ @api.get SERVICES, {}, (result) =>
19
+ @services = result.rows
20
+ this.drawServices()
21
+
22
+ drawServices: ->
23
+ return if $('#setup-page #services').length == 0
24
+ $('#services').empty()
25
+ for service in @services
26
+ node = $("""
27
+ <li>
28
+ <input id='service-#{service.id}' type='checkbox' value='#{service.id}'/>
29
+ <label for='service-#{service.id}'></label>
30
+ </li>
31
+ """).appendTo '#services'
32
+ $('label', node).text service.name
33
+ $('#services input[type="checkbox"]').val @selected.services if @selected
34
+ if @selected && !@selected.permissions['services']
35
+ $('#services input[type="checkbox"]').prop 'disabled', true
36
+
37
+ findUsers: ->
38
+ @api.get USERS, {}, (result) =>
39
+ @users = result.rows
40
+ this.drawUsers()
41
+
42
+ drawUsers: ->
43
+ return if $('#setup-page #users').length == 0
44
+ $('#users').empty()
45
+ systems = $('#systems-nav').hasClass 'selected'
46
+ for user in @users
47
+ this.userNode(user) if user.system == systems
48
+
49
+ userNode: (user) ->
50
+ node = $("""
51
+ <li data-name="" data-jid="" id="#{user.jid}">
52
+ <span class="text"></span>
53
+ <span class="jid"></span>
54
+ </li>
55
+ """).appendTo '#users'
56
+
57
+ name = this.userName(user)
58
+ $('.text', node).text name
59
+ $('.jid', node).text user.jid
60
+ node.attr 'data-name', name
61
+ node.attr 'data-jid', user.jid
62
+ node.click (event) => this.selectUser event.currentTarget
63
+ node
64
+
65
+ userName: (user) ->
66
+ user.name || user.jid.split('@')[0]
67
+
68
+ selectUser: (node) ->
69
+ jid = $(node).attr 'data-jid'
70
+ name = $(node).attr 'data-name'
71
+
72
+ $('#users li').removeClass 'selected'
73
+ $(node).addClass 'selected'
74
+
75
+ $('#remove-user-msg').html "Are you sure you want to remove " +
76
+ "<strong>#{name}</strong>?"
77
+ $('#remove-user-form .buttons').fadeIn 200
78
+ @api.get USERS, jid: jid, (result) =>
79
+ @selected = result
80
+ if result.system
81
+ this.drawSystemEditor result
82
+ else
83
+ this.drawUserEditor result
84
+
85
+ removeUser: ->
86
+ this.toggleForm '#remove-user-form'
87
+ selected = $("#users li[data-jid='#{@selected.jid}']")
88
+ @api.remove USERS, @selected.jid, (result) =>
89
+ selected.fadeOut 200, =>
90
+ @users = (u for u in @users when u.jid != @selected.jid)
91
+ selected.remove()
92
+ @selected = null
93
+ if $('#users-nav').hasClass 'selected'
94
+ this.drawUserBlankSlate()
95
+ else
96
+ this.drawSystemBlankSlate()
97
+ false
98
+
99
+ selectTask: (event) ->
100
+ @selected = null
101
+ $('#setup li').removeClass 'selected secondary'
102
+ $(event.currentTarget).addClass 'selected secondary'
103
+ switch $(event.currentTarget).attr('id')
104
+ when 'users-nav'
105
+ $('#beta-header').text 'Users'
106
+ this.drawUsers()
107
+ this.drawUserBlankSlate()
108
+ when 'systems-nav'
109
+ $('#beta-header').text 'Systems'
110
+ this.drawUsers()
111
+ this.drawSystemBlankSlate()
112
+
113
+ toggleForm: (form, fn) ->
114
+ form = $(form)
115
+ $('form.overlay').each ->
116
+ $(this).hide() unless this.id == form.attr 'id'
117
+ if form.is ':hidden'
118
+ fn() if fn
119
+ form.fadeIn 100
120
+ else
121
+ form.fadeOut 100, ->
122
+ form[0].reset()
123
+ fn() if fn
124
+
125
+ validateUser: ->
126
+ $('#user-name-error').empty()
127
+ $('#password-error').empty()
128
+ valid = true
129
+
130
+ node = $.trim $('#user-name').val()
131
+ password1 = $.trim $('#password1').val()
132
+ password2 = $.trim $('#password2').val()
133
+
134
+ if @selected # exisiting user
135
+ if password2.length > 0 && password2.length < 8
136
+ $('#password-error').text 'Password must be at least 8 characters.'
137
+ valid = false
138
+
139
+ else # new user
140
+ if node == ''
141
+ $('#user-name-error').text 'User name is required.'
142
+ valid = false
143
+
144
+ if node.match /[\s"&'\/:<>@]/
145
+ $('#user-name-error').text 'User name contains forbidden characters.'
146
+ valid = false
147
+
148
+ if password1.length == 0 || password2.length == 0
149
+ $('#password-error').text 'Password is required.'
150
+ valid = false
151
+
152
+ if password1 != password2
153
+ $('#password-error').text 'Passwords must match.'
154
+ valid = false
155
+
156
+ if password2.length < 8
157
+ $('#password-error').text 'Password must be at least 8 characters.'
158
+ valid = false
159
+
160
+ valid
161
+
162
+ saveUser: ->
163
+ return unless this.validateUser()
164
+ user =
165
+ jid: $('#jid').val()
166
+ username: $('#user-name').val()
167
+ name: $('#name').val()
168
+ password1: $('#password1').val()
169
+ password2: $('#password2').val()
170
+ services: $('#services :checked').map(-> $(this).val()).get()
171
+ permissions:
172
+ systems: $('#perm-systems').prop('checked')
173
+ services: $('#perm-services').prop('checked')
174
+ files: $('#perm-files').prop('checked')
175
+ users: $('#perm-users').prop('checked')
176
+
177
+ @api.save USERS, user, (result) =>
178
+ new Notification 'User saved successfully'
179
+ $('#jid').val result.jid
180
+ node = $("#users li[data-jid='#{result.jid}']")
181
+ if node.length == 0
182
+ @users.push result
183
+ node = this.userNode result
184
+ this.selectUser node
185
+ else
186
+ $('.text', node).text this.userName(result)
187
+ false
188
+
189
+ validateSystem: ->
190
+ $('#user-name-error').empty()
191
+ valid = true
192
+ node = $.trim $('#user-name').val()
193
+ unless @selected # new user
194
+ if node == ''
195
+ $('#user-name-error').text 'Hostname is required.'
196
+ valid = false
197
+
198
+ if node.match /[\s"&'\/:<>@]/
199
+ $('#user-name-error').text 'Hostname contains forbidden characters.'
200
+ valid = false
201
+ valid
202
+
203
+ saveSystem: ->
204
+ return unless this.validateSystem()
205
+ user =
206
+ jid: $('#jid').val()
207
+ username: $('#user-name').val()
208
+ password1: $('#password1').val()
209
+ password2: $('#password1').val()
210
+ system: true
211
+
212
+ @api.save USERS, user, (result) =>
213
+ new Notification 'System saved successfully'
214
+ $('#jid').val result.jid
215
+ node = $("#users li[data-jid='#{result.jid}']")
216
+ if node.length == 0
217
+ @users.push result
218
+ node = this.userNode result
219
+ this.selectUser node
220
+ else
221
+ $('.text', node).text result.name
222
+ false
223
+
224
+ rand: ->
225
+ Math.floor(Math.random() * 16)
226
+
227
+ token: ->
228
+ (this.rand().toString(16) for i in [0..127]).join('')
229
+
230
+ drawUserBlankSlate: ->
231
+ $('#charlie').empty()
232
+ $("""
233
+ <form id="blank-slate">
234
+ <p>
235
+ Select a user account to edit or add a new user.
236
+ </p>
237
+ <input type="submit" id="blank-slate-add" value="Add User"/>
238
+ </form>
239
+ """).appendTo '#charlie'
240
+ $('#blank-slate').submit =>
241
+ this.drawUserEditor()
242
+ false
243
+
244
+ drawSystemBlankSlate: ->
245
+ $('#charlie').empty()
246
+ $("""
247
+ <form id="blank-slate">
248
+ <p>
249
+ Systems need a user account before they can connect and
250
+ authenticate with the chat server.
251
+ </p>
252
+ <input type="submit" id="blank-slate-add" value="Add System"/>
253
+ </form>
254
+ """).appendTo '#charlie'
255
+ $('#blank-slate').submit =>
256
+ this.drawSystemEditor()
257
+ false
258
+
259
+ draw: ->
260
+ unless @session.connected()
261
+ window.location.hash = ''
262
+ return
263
+
264
+ $('body').attr 'id', 'setup-page'
265
+ $('#container').hide().empty()
266
+ $("""
267
+ <div id="alpha" class="sidebar column y-fill">
268
+ <h2>Setup</h2>
269
+ <ul id="setup" class="selectable scroll y-fill">
270
+ <li id="users-nav" class='selected secondary'>
271
+ <span class="text">Users</span>
272
+ </li>
273
+ <li id="systems-nav">
274
+ <span class="text">Systems</span>
275
+ </li>
276
+ </ul>
277
+ <div id="alpha-controls" class="controls"></div>
278
+ </div>
279
+ <div id="beta" class="sidebar column y-fill">
280
+ <h2><span id="beta-header">Users</span> <div id="search-users-icon"></div></h2>
281
+ <div id="search-users-form"></div>
282
+ <ul id="users" class="selectable scroll y-fill"></ul>
283
+ <form id="remove-user-form" class="overlay" style="display:none;">
284
+ <h2>Remove User</h2>
285
+ <p id="remove-user-msg">Select a user to delete.</p>
286
+ <fieldset class="buttons" style="display:none;">
287
+ <input id="remove-user-cancel" type="button" value="Cancel"/>
288
+ <input id="remove-user-ok" type="submit" value="Remove"/>
289
+ </fieldset>
290
+ </form>
291
+ <div id="beta-controls" class="controls">
292
+ <div id="add-user"></div>
293
+ <div id="remove-user"></div>
294
+ </div>
295
+ </div>
296
+ <div id="charlie" class="primary column x-fill y-fill"></div>
297
+ """).appendTo '#container'
298
+ this.drawUserBlankSlate()
299
+
300
+ $('#setup li').click (event) => this.selectTask event
301
+
302
+ this.findUsers()
303
+ this.findServices()
304
+
305
+ $('#container').show()
306
+ @layout = this.resize()
307
+
308
+ new Button '#add-user', ICONS.plus
309
+ new Button '#remove-user', ICONS.minus
310
+
311
+ $('#add-user').click =>
312
+ if $('#users-nav').hasClass 'selected'
313
+ this.drawUserEditor()
314
+ else
315
+ this.drawSystemEditor()
316
+
317
+ $('#remove-user').click => this.toggleForm '#remove-user-form'
318
+ $('#remove-user-cancel').click => this.toggleForm '#remove-user-form'
319
+ $('#remove-user-form').submit => this.removeUser()
320
+
321
+ fn = =>
322
+ @layout.resize()
323
+ @layout.resize() # not sure why two are needed
324
+
325
+ new Filter
326
+ list: '#users'
327
+ icon: '#search-users-icon'
328
+ form: '#search-users-form'
329
+ attrs: ['data-jid']
330
+ open: fn
331
+ close: fn
332
+
333
+ drawUserEditor: (user) ->
334
+ unless user
335
+ @selected = null
336
+ $('#users li').removeClass 'selected'
337
+
338
+ $('#charlie').empty()
339
+ $("""
340
+ <form id="editor-form" class="sections y-fill scroll">
341
+ <div>
342
+ <section>
343
+ <h2>User</h2>
344
+ <fieldset id="jid-fields">
345
+ <input id="jid" type="hidden" value=""/>
346
+ <label for="name">Real Name</label>
347
+ <input id="name" type="text" maxlength="1024"/>
348
+ </fieldset>
349
+ </section>
350
+ <section>
351
+ <h2>Password</h2>
352
+ <fieldset>
353
+ <label id="password1-label" for="password1">Current Password</label>
354
+ <input id="password1" type="password" maxlength="1024"/>
355
+ <label id="password2-label" for="password2">New Password</label>
356
+ <input id="password2" type="password" maxlength="1024"/>
357
+ <p id="password-error" class="error"></p>
358
+ </fieldset>
359
+ </section>
360
+ <section>
361
+ <h2>Permissions</h2>
362
+ <fieldset>
363
+ <label>Manage</label>
364
+ <ul id="permissions">
365
+ <li>
366
+ <input id="perm-systems" type="checkbox" value="systems"/>
367
+ <label for="perm-systems">Systems</label>
368
+ </li>
369
+ <li>
370
+ <input id="perm-services" type="checkbox" value="services"/>
371
+ <label for="perm-services">Services</label>
372
+ </li>
373
+ <li>
374
+ <input id="perm-users" type="checkbox" value="users"/>
375
+ <label for="perm-users">Users</label>
376
+ </li>
377
+ <li>
378
+ <input id="perm-files" type="checkbox" value="files"/>
379
+ <label for="perm-files">Files</label>
380
+ </li>
381
+ </ul>
382
+ </fieldset>
383
+ </section>
384
+ <section>
385
+ <h2>Services</h2>
386
+ <fieldset>
387
+ <label>Access To</label>
388
+ <ul id="services" class="scroll"></ul>
389
+ </fieldset>
390
+ </section>
391
+ </div>
392
+ </form>
393
+ <form id="editor-buttons">
394
+ <input id="save" type="submit" value="Save"/>
395
+ </form>
396
+ """).appendTo '#charlie'
397
+
398
+ if user
399
+ $("""
400
+ <label>Account Name</label>
401
+ <p>#{user.jid}</p>
402
+ """).prependTo '#jid-fields'
403
+
404
+ $('#name').focus()
405
+
406
+ $('#jid').val user.jid
407
+ $('#name').val user.name
408
+ $('#user-name').val user.jid.split('@')[0]
409
+ for name in 'services systems files users'.split(' ')
410
+ $("#perm-#{name}").prop('checked', true) if user.permissions[name]
411
+ $("#perm-#{name}").prop('disabled', true) if @session.bareJid() == user.jid
412
+ else
413
+ $("""
414
+ <label for="user-name">User Name</label>
415
+ <input id="user-name" type="text" maxlength="1023"/>
416
+ <p id="user-name-error" class="error"></p>
417
+ """).prependTo '#jid-fields'
418
+ $('#password1-label').text 'Password'
419
+ $('#password2-label').text 'Password Again'
420
+ $('#user-name').focus()
421
+
422
+ this.drawServices() if @services.length > 0
423
+
424
+ @layout.resize()
425
+ $('#editor-form').submit => this.saveUser()
426
+ $('#editor-buttons').submit => this.saveUser()
427
+
428
+ drawSystemEditor: (user) ->
429
+ unless user
430
+ @selected = null
431
+ $('#users li').removeClass 'selected'
432
+
433
+ $('#charlie').empty()
434
+ $("""
435
+ <form id="editor-form" class="sections y-fill scroll">
436
+ <div>
437
+ <section>
438
+ <h2>System</h2>
439
+ <fieldset id="jid-fields">
440
+ <input id="jid" type="hidden" value=""/>
441
+ <label id="password1-label" for="password1">Authentication Token</label>
442
+ <div id="token-container">
443
+ <input id="password1" type="text" readonly placeholder="Press Generate to create a new token"/>
444
+ <input id="new-token" type="button" value="Generate"/>
445
+ </div>
446
+ </fieldset>
447
+ </section>
448
+ <section id="info">
449
+ <h2>Info</h2>
450
+ <fieldset>
451
+ <label>Platform</label>
452
+ <p id="info-platform">-</p>
453
+ <label>Hostname</label>
454
+ <p id="info-fqdn">-</p>
455
+ <label>IP Address</label>
456
+ <p id="info-ip">-</p>
457
+ <label>MAC Address</label>
458
+ <p id="info-mac">-</p>
459
+ </fieldset>
460
+ </section>
461
+ </div>
462
+ </form>
463
+ <form id="editor-buttons">
464
+ <input id="save" type="submit" value="Save"/>
465
+ </form>
466
+ """).appendTo '#charlie'
467
+
468
+ $('#new-token').click => $('#password1').val this.token()
469
+
470
+ this.findSystem(user.jid.split('@')[0]) if user
471
+
472
+ if user
473
+ $("""
474
+ <label>Account Name</label>
475
+ <p>#{user.jid}</p>
476
+ """).prependTo '#jid-fields'
477
+ $('#jid').val user.jid
478
+ $('#user-name').val user.jid.split('@')[0]
479
+ else
480
+ $("""
481
+ <label for="user-name">Hostname</label>
482
+ <input id="user-name" type="text" maxlength="1023"/>
483
+ <p id="user-name-error" class="error"></p>
484
+ """).prependTo '#jid-fields'
485
+ $('#user-name').focus()
486
+ $('#password1').val this.token()
487
+
488
+ @layout.resize()
489
+ $('#editor-form').submit => this.saveSystem()
490
+ $('#editor-buttons').submit => this.saveSystem()
491
+
492
+ drawSystemInfo: (system) ->
493
+ $('#info-platform').text system.platform
494
+ $('#info-fqdn').text system.fqdn
495
+ $('#info-ip').text system.ipaddress
496
+ $('#info-mac').text system.macaddress
497
+
498
+ resize: ->
499
+ a = $ '#alpha'
500
+ b = $ '#beta'
501
+ c = $ '#charlie'
502
+ new Layout ->
503
+ c.css 'left', a.outerWidth() + b.outerWidth()