vines-services 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +5 -5
- data/Rakefile +13 -11
- data/bin/vines-services +0 -1
- data/lib/vines/services/command/init.rb +156 -139
- data/lib/vines/services/controller/messages_controller.rb +8 -3
- data/lib/vines/services/controller/users_controller.rb +11 -11
- data/lib/vines/services/indexer.rb +1 -1
- data/lib/vines/services/priority_queue.rb +12 -12
- data/lib/vines/services/roster.rb +85 -46
- data/lib/vines/services/storage/couchdb/service.rb +1 -1
- data/lib/vines/services/storage/couchdb/system.rb +1 -1
- data/lib/vines/services/storage/couchdb/upload.rb +1 -1
- data/lib/vines/services/storage/couchdb/user.rb +13 -3
- data/lib/vines/services/storage/couchdb.rb +8 -12
- data/lib/vines/services/version.rb +1 -1
- data/test/priority_queue_test.rb +1 -1
- data/web/coffeescripts/api.coffee +6 -0
- data/web/coffeescripts/files.coffee +65 -39
- data/web/coffeescripts/services.coffee +5 -2
- data/web/coffeescripts/setup.coffee +35 -12
- data/web/coffeescripts/systems.coffee +115 -228
- data/web/javascripts/api.js +69 -0
- data/web/javascripts/app.js +2 -0
- data/web/javascripts/commands.js +28 -0
- data/web/javascripts/files.js +424 -0
- data/web/javascripts/init.js +27 -0
- data/web/javascripts/services.js +404 -0
- data/web/javascripts/setup.js +485 -0
- data/web/javascripts/systems.js +342 -0
- data/web/stylesheets/app.css +714 -0
- data/web/stylesheets/services.css +4 -14
- data/web/stylesheets/setup.css +1 -2
- data/web/stylesheets/systems.css +124 -108
- metadata +95 -92
@@ -1,70 +1,109 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
+
|
2
3
|
module Vines
|
3
4
|
class Storage
|
4
5
|
class CouchDB < Storage
|
6
|
+
alias :_services_find_user :find_user
|
7
|
+
|
8
|
+
# Override the user's roster with an auto-populated roster containing
|
9
|
+
# the services and systems to which the user has permission to access.
|
10
|
+
def find_user(jid)
|
11
|
+
user = _services_find_user(jid)
|
12
|
+
return unless user
|
13
|
+
user.roster = []
|
14
|
+
|
15
|
+
systems, users = find_users.partition {|u| u['system'] }
|
16
|
+
systems.map! {|u| u['_id'].sub('user:', '') }
|
17
|
+
return user if systems.include?(user.jid.to_s)
|
18
|
+
services = find_services(user.jid)
|
19
|
+
|
20
|
+
users.each do |row|
|
21
|
+
id = row['_id'].sub('user:', '')
|
22
|
+
user.roster << Contact.new(
|
23
|
+
:jid => id,
|
24
|
+
:name => row['name'],
|
25
|
+
:subscription => 'both',
|
26
|
+
:groups => ['People']) unless id == jid.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
services.each do |row|
|
30
|
+
user.roster << Contact.new(
|
31
|
+
:jid => row['jid'],
|
32
|
+
:name => row['name'],
|
33
|
+
:subscription => 'to',
|
34
|
+
:groups => ['Services'])
|
35
|
+
end
|
36
|
+
|
37
|
+
find_systems(services).each do |name, groups|
|
38
|
+
id = JID.new(name.dup, user.jid.domain).to_s
|
39
|
+
user.roster << Contact.new(
|
40
|
+
:jid => id,
|
41
|
+
:name => name,
|
42
|
+
:subscription => 'to',
|
43
|
+
:groups => ['Systems', *groups]) if systems.include?(id)
|
44
|
+
end
|
5
45
|
|
6
|
-
|
46
|
+
user.roster << Contact.new(
|
47
|
+
:jid => "vines.#{user.jid.domain}",
|
48
|
+
:name => 'Vines',
|
49
|
+
:subscription => 'to')
|
50
|
+
user
|
51
|
+
end
|
7
52
|
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
http = EM::HttpRequest.new(
|
12
|
-
http.errback { yield }
|
53
|
+
# Return the User documents for all users and systems.
|
54
|
+
def find_users
|
55
|
+
url = "%s/_design/User/_view/all?reduce=false&include_docs=true" % @url
|
56
|
+
http = EM::HttpRequest.new(url).get
|
57
|
+
http.errback { yield [] }
|
13
58
|
http.callback do
|
14
59
|
doc = if http.response_header.status == 200
|
15
|
-
JSON.parse(http.response) rescue
|
60
|
+
rows = JSON.parse(http.response)['rows'] rescue []
|
61
|
+
rows.map {|row| row['doc'] }
|
16
62
|
end
|
17
|
-
yield doc
|
63
|
+
yield doc || []
|
18
64
|
end
|
19
65
|
end
|
66
|
+
fiber :find_users
|
20
67
|
|
21
|
-
#
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
if doc['roster'] != ""
|
32
|
-
(doc['roster'] || {}).each_pair do |jid, props|
|
33
|
-
user.roster << Contact.new(
|
34
|
-
:jid => jid,
|
35
|
-
:name => props['name'],
|
36
|
-
:subscription => props['subscription'],
|
37
|
-
:ask => props['ask'],
|
38
|
-
:groups => props['groups'] || [])
|
39
|
-
end
|
40
|
-
end
|
41
|
-
add_user_roster_services(user)
|
42
|
-
end
|
68
|
+
# Return the Service documents to which this JID has permission to
|
69
|
+
# access.
|
70
|
+
def find_services(jid)
|
71
|
+
url = "%s/_design/Service/_view/by_user?reduce=false&key=%s" % [@url, escape(jid.to_s).to_json]
|
72
|
+
http = EM::HttpRequest.new(url).get
|
73
|
+
http.errback { yield [] }
|
74
|
+
http.callback do
|
75
|
+
doc = if http.response_header.status == 200
|
76
|
+
rows = JSON.parse(http.response)['rows'] rescue []
|
77
|
+
rows.map {|row| row['value'] }
|
43
78
|
end
|
44
|
-
yield
|
79
|
+
yield doc || []
|
45
80
|
end
|
46
81
|
end
|
47
|
-
fiber :
|
82
|
+
fiber :find_services
|
48
83
|
|
49
|
-
#
|
50
|
-
#
|
51
|
-
def
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
84
|
+
# Find the systems that belong to these services. Return a Hash of
|
85
|
+
# system name to list of service names to which it belongs.
|
86
|
+
def find_systems(services)
|
87
|
+
keys = services.map {|row| [0, row['_id']] }
|
88
|
+
url = "%s/_design/System/_view/memberships?reduce=false" % @url
|
89
|
+
http = EM::HttpRequest.new(url).post(
|
90
|
+
head: {'Content-Type' => 'application/json'},
|
91
|
+
body: {keys: keys}.to_json)
|
92
|
+
http.errback { yield [] }
|
93
|
+
http.callback do
|
94
|
+
doc = if http.response_header.status == 200
|
95
|
+
rows = JSON.parse(http.response)['rows'] rescue []
|
96
|
+
Hash.new {|h, k| h[k] = [] }.tap do |systems|
|
97
|
+
rows.each do |row|
|
98
|
+
service = services.find {|s| s['_id'] == row['key'][1] }
|
99
|
+
systems[row['value']['name']] << service['name']
|
63
100
|
end
|
64
101
|
end
|
65
102
|
end
|
103
|
+
yield doc || []
|
66
104
|
end
|
67
105
|
end
|
106
|
+
fiber :find_systems
|
68
107
|
end
|
69
108
|
end
|
70
109
|
end
|
@@ -6,7 +6,7 @@ module Vines
|
|
6
6
|
class Service < CouchRest::Model::Base
|
7
7
|
extend Storage::CouchDB::ClassMethods
|
8
8
|
|
9
|
-
KEYS = %w[_id name code accounts users jid created_at
|
9
|
+
KEYS = %w[_id name code accounts users jid created_at updated_at].freeze
|
10
10
|
VIEW_ID = "_design/System".freeze
|
11
11
|
VIEW_NAME = "System/memberships".freeze
|
12
12
|
|
@@ -6,7 +6,7 @@ module Vines
|
|
6
6
|
class System < CouchRest::Model::Base
|
7
7
|
extend Storage::CouchDB::ClassMethods
|
8
8
|
|
9
|
-
KEYS = %w[_id ohai created_at
|
9
|
+
KEYS = %w[_id ohai created_at updated_at].freeze
|
10
10
|
VIEW_NAME = "System/memberships".freeze
|
11
11
|
|
12
12
|
attr_writer :services
|
@@ -6,7 +6,7 @@ module Vines
|
|
6
6
|
class Upload < CouchRest::Model::Base
|
7
7
|
extend Storage::CouchDB::ClassMethods
|
8
8
|
|
9
|
-
KEYS = %w[_id name size labels created_at
|
9
|
+
KEYS = %w[_id name size labels created_at updated_at].freeze
|
10
10
|
|
11
11
|
property :name, String
|
12
12
|
property :size, Integer
|
@@ -6,7 +6,7 @@ module Vines
|
|
6
6
|
class User < CouchRest::Model::Base
|
7
7
|
extend Storage::CouchDB::ClassMethods
|
8
8
|
|
9
|
-
KEYS = %w[_id name permissions system created_at
|
9
|
+
KEYS = %w[_id name permissions system created_at updated_at].freeze
|
10
10
|
|
11
11
|
before_save :enforce_constraints
|
12
12
|
after_destroy :remove_references
|
@@ -51,6 +51,16 @@ module Vines
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
# Grant this user all possible permissions.
|
55
|
+
def admin!
|
56
|
+
write_attribute('permissions', {
|
57
|
+
'systems' => true,
|
58
|
+
'services' => true,
|
59
|
+
'files' => true,
|
60
|
+
'users' => true
|
61
|
+
})
|
62
|
+
end
|
63
|
+
|
54
64
|
def permissions=(perms)
|
55
65
|
perms ||= {}
|
56
66
|
self.manage_systems = perms['systems']
|
@@ -59,7 +69,7 @@ module Vines
|
|
59
69
|
self.manage_users = perms['users']
|
60
70
|
end
|
61
71
|
|
62
|
-
def
|
72
|
+
def plain_password=(desired)
|
63
73
|
desired = (desired || '').strip
|
64
74
|
raise 'password too short' if desired.size < (system ? 128 : 8)
|
65
75
|
write_attribute('password', BCrypt::Password.create(desired))
|
@@ -68,7 +78,7 @@ module Vines
|
|
68
78
|
def change_password(previous, desired)
|
69
79
|
hash = BCrypt::Password.new(password) rescue nil
|
70
80
|
raise 'password failure' unless hash && hash == previous
|
71
|
-
self.
|
81
|
+
self.plain_password = desired
|
72
82
|
end
|
73
83
|
|
74
84
|
def jid
|
@@ -100,20 +100,13 @@ module Vines
|
|
100
100
|
end
|
101
101
|
|
102
102
|
def create_views
|
103
|
-
# FIXME Use views in CouchRest::Model classes to populate db
|
104
|
-
designs = {}
|
105
|
-
|
106
103
|
EM.run do
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
doc ||= {"_id" => "_design/#{name}"}
|
111
|
-
doc['language'] = 'javascript'
|
112
|
-
doc['views'] = views
|
113
|
-
save(doc) { EM.stop }
|
114
|
-
end
|
104
|
+
Fiber.new do
|
105
|
+
CouchRest::Model::Base.subclasses.each do |klass|
|
106
|
+
klass.save_design_doc! if klass.respond_to?(:save_design_doc!)
|
115
107
|
end
|
116
|
-
|
108
|
+
EM.stop
|
109
|
+
end.resume
|
117
110
|
end
|
118
111
|
end
|
119
112
|
|
@@ -146,6 +139,9 @@ module Vines
|
|
146
139
|
*url, _ = @url.split('/')
|
147
140
|
server = CouchRest::Server.new(url.join('/'))
|
148
141
|
CouchRest::Model::Base.database = server.database(database)
|
142
|
+
CouchRest::Model::Base.configure do |config|
|
143
|
+
config.auto_update_design_doc = false
|
144
|
+
end
|
149
145
|
end
|
150
146
|
|
151
147
|
def escape(jid)
|
data/test/priority_queue_test.rb
CHANGED
@@ -9,8 +9,7 @@ class FilesPage
|
|
9
9
|
jid: @api.jid
|
10
10
|
size: this.size
|
11
11
|
complete: (file) =>
|
12
|
-
this.
|
13
|
-
this.findFiles name: file.name
|
12
|
+
this.findFile file.name
|
14
13
|
|
15
14
|
findLabels: ->
|
16
15
|
$('#labels').empty()
|
@@ -20,7 +19,7 @@ class FilesPage
|
|
20
19
|
labelNodeList: (label)->
|
21
20
|
text = if label.size == 1 then 'file' else 'files'
|
22
21
|
node = $("""
|
23
|
-
<li data-name=""
|
22
|
+
<li data-name="">
|
24
23
|
<span class="text"></span>
|
25
24
|
<span class="count">#{label.size} #{text}</span>
|
26
25
|
</li>
|
@@ -28,7 +27,6 @@ class FilesPage
|
|
28
27
|
$('.text', node).text label.name
|
29
28
|
node.attr 'data-name', label.name
|
30
29
|
node.click (event) => this.selectLabel(event)
|
31
|
-
node.fadeIn(100)
|
32
30
|
|
33
31
|
selectLabel: (event) ->
|
34
32
|
name = $(event.currentTarget).attr 'data-name'
|
@@ -41,19 +39,35 @@ class FilesPage
|
|
41
39
|
@api.get FILES, criteria, (result) =>
|
42
40
|
this.fileNode row for row in result.rows
|
43
41
|
|
44
|
-
|
42
|
+
findFile: (name) ->
|
43
|
+
@api.get FILES, name: name, (result) =>
|
44
|
+
this.fileNode result
|
45
|
+
|
46
|
+
updateFileNode: (file) ->
|
47
|
+
node = $ "#files li[data-id='#{file.id}']"
|
45
48
|
size = this.size file.size
|
46
|
-
if !file.created_at
|
47
|
-
file.created_at = Date()
|
48
49
|
time = this.date file.created_at
|
50
|
+
node.data 'file', file
|
51
|
+
$('h2', node).text file.name
|
52
|
+
$('.size', node).text size
|
53
|
+
$('.time', node).text time
|
54
|
+
node.attr 'data-name', file.name
|
55
|
+
node.attr 'data-size', size
|
56
|
+
node.attr 'data-created', time
|
57
|
+
|
58
|
+
fileNode: (file) ->
|
59
|
+
if $("#files li[data-id='#{file.id}']").length > 0
|
60
|
+
this.updateFileNode file
|
61
|
+
return
|
62
|
+
|
49
63
|
node = $("""
|
50
|
-
<li data-id="#{file.id}"
|
64
|
+
<li data-id="#{file.id}">
|
51
65
|
<div class="file-icon">
|
52
|
-
<span class="size"
|
66
|
+
<span class="size"></span>
|
53
67
|
</div>
|
54
68
|
<h2></h2>
|
55
69
|
<footer>
|
56
|
-
<span class="time"
|
70
|
+
<span class="time"></span>
|
57
71
|
<ul class="labels"></ul>
|
58
72
|
<form class="add-label">
|
59
73
|
<div class="add-label-button"></div>
|
@@ -68,10 +82,6 @@ class FilesPage
|
|
68
82
|
</li>
|
69
83
|
""").appendTo '#files'
|
70
84
|
|
71
|
-
node.data 'file', file
|
72
|
-
$('h2', node).text file.name
|
73
|
-
node.attr 'data-name', file.name
|
74
|
-
|
75
85
|
new Button $('.file-icon', node).get(0), ICONS.page2,
|
76
86
|
scale: 1.0
|
77
87
|
translation: '-2 0'
|
@@ -87,7 +97,8 @@ class FilesPage
|
|
87
97
|
$('.add-label-button', node).click ->
|
88
98
|
$('form.add-label input[type="text"]', node).show()
|
89
99
|
|
90
|
-
this.
|
100
|
+
this.updateFileNode file
|
101
|
+
this.labelNode(node, label) for label in file.labels
|
91
102
|
|
92
103
|
labelNode: (node, label) ->
|
93
104
|
labels = $('.labels', node)
|
@@ -115,8 +126,9 @@ class FilesPage
|
|
115
126
|
file = node.data 'file'
|
116
127
|
file.labels.push label for label in labels
|
117
128
|
@api.save FILES, file, (result) ->
|
118
|
-
|
119
|
-
|
129
|
+
for label in labels
|
130
|
+
this.labelNode node, label
|
131
|
+
this.updateLabelCount label, 1
|
120
132
|
false
|
121
133
|
|
122
134
|
removeLabel: (node, item) ->
|
@@ -125,10 +137,21 @@ class FilesPage
|
|
125
137
|
file.labels = (label for label in file.labels when label != remove)
|
126
138
|
@api.save FILES, file, (result) ->
|
127
139
|
item.fadeOut 200, -> item.remove()
|
128
|
-
this.
|
140
|
+
this.updateLabelCount remove, -1
|
141
|
+
|
142
|
+
updateLabelCount: (name, inc) ->
|
143
|
+
el = $ "#labels li[data-name='#{name}'] .count"
|
144
|
+
if el.length > 0
|
145
|
+
count = parseInt(el.text().split(' ')[0]) + inc
|
146
|
+
text = if count == 1 then 'file' else 'files'
|
147
|
+
el.text "#{count} #{text}"
|
148
|
+
else
|
149
|
+
this.labelNodeList(name: name, size: 1)
|
129
150
|
|
130
151
|
deleteFile: (node) ->
|
131
152
|
@api.remove FILES, node.attr('data-id'), (result) =>
|
153
|
+
for label in node.data('file').labels
|
154
|
+
this.updateLabelCount label, -1
|
132
155
|
node.fadeOut 200, -> node.remove()
|
133
156
|
false
|
134
157
|
|
@@ -188,31 +211,35 @@ class FilesPage
|
|
188
211
|
</div>
|
189
212
|
""").appendTo '#container'
|
190
213
|
|
191
|
-
|
192
|
-
|
193
|
-
|
214
|
+
if @api.user.permissions.files
|
215
|
+
$('#file-chooser').change (event) =>
|
216
|
+
@uploads.queue event.target.files
|
217
|
+
$('#file-chooser').val ''
|
194
218
|
|
195
|
-
|
196
|
-
|
197
|
-
|
219
|
+
$('#file-form').submit ->
|
220
|
+
$('#file-chooser').click()
|
221
|
+
false
|
198
222
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
223
|
+
$('#upload-dnd').bind 'dragenter', (event) ->
|
224
|
+
event.stopPropagation()
|
225
|
+
event.preventDefault()
|
226
|
+
$('#upload-dnd').css 'color', '#444'
|
203
227
|
|
204
|
-
|
205
|
-
|
228
|
+
$('#upload-dnd').bind 'dragleave', (event) ->
|
229
|
+
$('#upload-dnd').css 'color', '#ababab'
|
206
230
|
|
207
|
-
|
208
|
-
|
209
|
-
|
231
|
+
$('#upload-dnd').bind 'dragover', (event) ->
|
232
|
+
event.stopPropagation()
|
233
|
+
event.preventDefault()
|
210
234
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
235
|
+
$('#upload-dnd').bind 'drop', (event) =>
|
236
|
+
event.stopPropagation()
|
237
|
+
event.preventDefault()
|
238
|
+
$('#upload-dnd').css 'color', '#ababab'
|
239
|
+
@uploads.queue event.originalEvent.dataTransfer.files
|
240
|
+
else
|
241
|
+
$('#upload-dnd').text "Your account cannot upload files."
|
242
|
+
$('#file-form').remove()
|
216
243
|
|
217
244
|
this.findLabels()
|
218
245
|
this.findFiles()
|
@@ -278,7 +305,6 @@ class FilesPage
|
|
278
305
|
upload.start()
|
279
306
|
else
|
280
307
|
@sending = null
|
281
|
-
this.fileNode(upload.file)
|
282
308
|
|
283
309
|
find: (file) ->
|
284
310
|
(up for up in @uploads when up.file.name == file.name).shift()
|
@@ -173,9 +173,10 @@ class ServicesPage
|
|
173
173
|
criteria you define. Send a command to the service and it runs
|
174
174
|
on every system in the group.
|
175
175
|
</p>
|
176
|
-
<input type="submit" id="blank-slate-add" value="
|
176
|
+
<input type="submit" id="blank-slate-add" value="Add Service"/>
|
177
177
|
</form>
|
178
178
|
""").appendTo '#beta'
|
179
|
+
$('#blank-slate-add').remove() unless @api.user.permissions.services
|
179
180
|
$('#blank-slate').submit =>
|
180
181
|
this.drawEditor()
|
181
182
|
false
|
@@ -218,6 +219,8 @@ class ServicesPage
|
|
218
219
|
new Button '#add-service', ICONS.plus
|
219
220
|
new Button '#remove-service', ICONS.minus
|
220
221
|
|
222
|
+
$('#alpha-controls div').remove() unless @api.user.permissions.services
|
223
|
+
|
221
224
|
this.drawBlankSlate()
|
222
225
|
|
223
226
|
$('#add-service').click => this.drawEditor()
|
@@ -272,7 +275,7 @@ class ServicesPage
|
|
272
275
|
<input id="name" type="text"/>
|
273
276
|
<p id="name-error" class="error"></p>
|
274
277
|
<label for="syntax">Criteria</label>
|
275
|
-
<textarea id="syntax" placeholder="fqdn
|
278
|
+
<textarea id="syntax" placeholder="fqdn starts with 'www.' and platform is 'mac_os_x'"></textarea>
|
276
279
|
<p id="syntax-status"></p>
|
277
280
|
</fieldset>
|
278
281
|
</section>
|
@@ -31,7 +31,7 @@ class SetupPage
|
|
31
31
|
""").appendTo '#services'
|
32
32
|
$('label', node).text service.name
|
33
33
|
$('#services input[type="checkbox"]').val @selected.services if @selected
|
34
|
-
if @selected && !@
|
34
|
+
if @selected && !@api.user.permissions.services
|
35
35
|
$('#services input[type="checkbox"]').prop 'disabled', true
|
36
36
|
|
37
37
|
findUsers: ->
|
@@ -48,17 +48,15 @@ class SetupPage
|
|
48
48
|
|
49
49
|
userNode: (user) ->
|
50
50
|
node = $("""
|
51
|
-
<li data-name="" data-jid="" id="#{user.jid}">
|
51
|
+
<li data-name="" data-jid="#{user.jid}" id="#{user.jid}">
|
52
52
|
<span class="text"></span>
|
53
|
-
<span class="jid"
|
53
|
+
<span class="jid">#{user.jid}</span>
|
54
54
|
</li>
|
55
55
|
""").appendTo '#users'
|
56
56
|
|
57
57
|
name = this.userName(user)
|
58
58
|
$('.text', node).text name
|
59
|
-
$('.jid', node).text user.jid
|
60
59
|
node.attr 'data-name', name
|
61
|
-
node.attr 'data-jid', user.jid
|
62
60
|
node.click (event) => this.selectUser event.currentTarget
|
63
61
|
node
|
64
62
|
|
@@ -105,10 +103,18 @@ class SetupPage
|
|
105
103
|
$('#beta-header').text 'Users'
|
106
104
|
this.drawUsers()
|
107
105
|
this.drawUserBlankSlate()
|
106
|
+
if @api.user.permissions.users
|
107
|
+
$('#beta-controls div').show()
|
108
|
+
else
|
109
|
+
$('#beta-controls div').hide()
|
108
110
|
when 'systems-nav'
|
109
111
|
$('#beta-header').text 'Systems'
|
110
112
|
this.drawUsers()
|
111
113
|
this.drawSystemBlankSlate()
|
114
|
+
if @api.user.permissions.systems
|
115
|
+
$('#beta-controls div').show()
|
116
|
+
else
|
117
|
+
$('#beta-controls div').hide()
|
112
118
|
|
113
119
|
toggleForm: (form, fn) ->
|
114
120
|
form = $(form)
|
@@ -136,6 +142,12 @@ class SetupPage
|
|
136
142
|
$('#password-error').text 'Password must be at least 8 characters.'
|
137
143
|
valid = false
|
138
144
|
|
145
|
+
# admin updating a user's password
|
146
|
+
if @session.bareJid() != @selected.jid
|
147
|
+
if password1 != password2
|
148
|
+
$('#password-error').text 'Passwords must match.'
|
149
|
+
valid = false
|
150
|
+
|
139
151
|
else # new user
|
140
152
|
if node == ''
|
141
153
|
$('#user-name-error').text 'User name is required.'
|
@@ -160,7 +172,7 @@ class SetupPage
|
|
160
172
|
valid
|
161
173
|
|
162
174
|
saveUser: ->
|
163
|
-
return unless this.validateUser()
|
175
|
+
return false unless this.validateUser()
|
164
176
|
user =
|
165
177
|
jid: $('#jid').val()
|
166
178
|
username: $('#user-name').val()
|
@@ -201,7 +213,7 @@ class SetupPage
|
|
201
213
|
valid
|
202
214
|
|
203
215
|
saveSystem: ->
|
204
|
-
return unless this.validateSystem()
|
216
|
+
return false unless this.validateSystem()
|
205
217
|
user =
|
206
218
|
jid: $('#jid').val()
|
207
219
|
username: $('#user-name').val()
|
@@ -229,14 +241,18 @@ class SetupPage
|
|
229
241
|
|
230
242
|
drawUserBlankSlate: ->
|
231
243
|
$('#charlie').empty()
|
244
|
+
msg = if @api.user.permissions.users
|
245
|
+
'Select a user account to update or add a new user.'
|
246
|
+
else
|
247
|
+
'Select a user account to update.'
|
248
|
+
|
232
249
|
$("""
|
233
250
|
<form id="blank-slate">
|
234
|
-
<p>
|
235
|
-
Select a user account to edit or add a new user.
|
236
|
-
</p>
|
251
|
+
<p>#{msg}</p>
|
237
252
|
<input type="submit" id="blank-slate-add" value="Add User"/>
|
238
253
|
</form>
|
239
254
|
""").appendTo '#charlie'
|
255
|
+
$('#blank-slate-add').remove() unless @api.user.permissions.users
|
240
256
|
$('#blank-slate').submit =>
|
241
257
|
this.drawUserEditor()
|
242
258
|
false
|
@@ -252,6 +268,7 @@ class SetupPage
|
|
252
268
|
<input type="submit" id="blank-slate-add" value="Add System"/>
|
253
269
|
</form>
|
254
270
|
""").appendTo '#charlie'
|
271
|
+
$('#blank-slate-add').remove() unless @api.user.permissions.systems
|
255
272
|
$('#blank-slate').submit =>
|
256
273
|
this.drawSystemEditor()
|
257
274
|
false
|
@@ -295,6 +312,7 @@ class SetupPage
|
|
295
312
|
</div>
|
296
313
|
<div id="charlie" class="primary column x-fill y-fill"></div>
|
297
314
|
""").appendTo '#container'
|
315
|
+
|
298
316
|
this.drawUserBlankSlate()
|
299
317
|
|
300
318
|
$('#setup li').click (event) => this.selectTask event
|
@@ -308,6 +326,9 @@ class SetupPage
|
|
308
326
|
new Button '#add-user', ICONS.plus
|
309
327
|
new Button '#remove-user', ICONS.minus
|
310
328
|
|
329
|
+
$('#beta-controls div').hide() unless @api.user.permissions.users
|
330
|
+
$('#systems-nav').hide() unless @api.user.permissions.systems
|
331
|
+
|
311
332
|
$('#add-user').click =>
|
312
333
|
if $('#users-nav').hasClass 'selected'
|
313
334
|
this.drawUserEditor()
|
@@ -326,7 +347,7 @@ class SetupPage
|
|
326
347
|
list: '#users'
|
327
348
|
icon: '#search-users-icon'
|
328
349
|
form: '#search-users-form'
|
329
|
-
attrs: ['data-jid']
|
350
|
+
attrs: ['data-jid', 'data-name']
|
330
351
|
open: fn
|
331
352
|
close: fn
|
332
353
|
|
@@ -402,7 +423,9 @@ class SetupPage
|
|
402
423
|
""").prependTo '#jid-fields'
|
403
424
|
|
404
425
|
$('#name').focus()
|
405
|
-
|
426
|
+
if @session.bareJid() != user.jid
|
427
|
+
$('#password1-label').text 'Password'
|
428
|
+
$('#password2-label').text 'Password Again'
|
406
429
|
$('#jid').val user.jid
|
407
430
|
$('#name').val user.name
|
408
431
|
$('#user-name').val user.jid.split('@')[0]
|