root / snf-cyclades-app / synnefo / ui / static / snf / js / ui / web / ui_public_keys_view.js @ 363538b2
History | View | Annotate | Download (11.6 kB)
1 |
// Copyright 2013 GRNET S.A. All rights reserved.
|
---|---|
2 |
//
|
3 |
// Redistribution and use in source and binary forms, with or
|
4 |
// without modification, are permitted provided that the following
|
5 |
// conditions are met:
|
6 |
//
|
7 |
// 1. Redistributions of source code must retain the above
|
8 |
// copyright notice, this list of conditions and the following
|
9 |
// disclaimer.
|
10 |
//
|
11 |
// 2. Redistributions in binary form must reproduce the above
|
12 |
// copyright notice, this list of conditions and the following
|
13 |
// disclaimer in the documentation and/or other materials
|
14 |
// provided with the distribution.
|
15 |
//
|
16 |
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
17 |
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18 |
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
19 |
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
|
20 |
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
21 |
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
22 |
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
23 |
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
24 |
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 |
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
26 |
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27 |
// POSSIBILITY OF SUCH DAMAGE.
|
28 |
//
|
29 |
// The views and conclusions contained in the software and
|
30 |
// documentation are those of the authors and should not be
|
31 |
// interpreted as representing official policies, either expressed
|
32 |
// or implied, of GRNET S.A.
|
33 |
//
|
34 |
|
35 |
;(function(root){
|
36 |
|
37 |
// root
|
38 |
var root = root;
|
39 |
|
40 |
// setup namepsaces
|
41 |
var snf = root.synnefo = root.synnefo || {};
|
42 |
var models = snf.models = snf.models || {}
|
43 |
var storage = snf.storage = snf.storage || {};
|
44 |
var ui = snf.ui = snf.ui || {};
|
45 |
var util = snf.util || {};
|
46 |
var views = snf.views = snf.views || {}
|
47 |
|
48 |
// shortcuts
|
49 |
var bb = root.Backbone;
|
50 |
|
51 |
// logging
|
52 |
var logger = new snf.logging.logger("SNF-VIEWS"); |
53 |
var debug = _.bind(logger.debug, logger);
|
54 |
|
55 |
views.PublicKeyCreateView = views.Overlay.extend({ |
56 |
view_id: "public_key_create_view", |
57 |
|
58 |
content_selector: "#public-key-create-content", |
59 |
css_class: 'overlay-public-key-create overlay-info', |
60 |
overlay_id: "public_key_create_view", |
61 |
|
62 |
subtitle: "", |
63 |
title: "Create new keypair", |
64 |
|
65 |
initialize: function() { |
66 |
views.PublicKeyCreateView.__super__.initialize.apply(this, arguments); |
67 |
this.form = this.$("form.model-form"); |
68 |
this.submit = this.$(".form-actions .submit"); |
69 |
this.cancel = this.$(".form-actions .cancel"); |
70 |
this.close = this.$(".form-actions .close"); |
71 |
this.error = this.$(".error-msg"); |
72 |
this.model_actions = this.$(".model-actions"); |
73 |
this.form_actions_cont = this.$(".form-actions"); |
74 |
this.form_actions = this.$(".form-actions .form-action"); |
75 |
|
76 |
this.input_name = this.form.find(".input-name"); |
77 |
this.input_key = this.form.find("textarea"); |
78 |
this.input_file = this.form.find(".content-input-file"); |
79 |
|
80 |
this.generate_action = this.$(".model-action.generate"); |
81 |
this.generate_msg = this.$(".generate-msg"); |
82 |
this.generate_download = this.generate_msg.find(".download"); |
83 |
this.generate_success = this.generate_msg.find(".success"); |
84 |
|
85 |
this.generating = false; |
86 |
this.in_progress = false; |
87 |
this.init_handlers();
|
88 |
}, |
89 |
|
90 |
_init_reader: function() { |
91 |
var opts = {
|
92 |
dragClass: "drag", |
93 |
accept: false, |
94 |
readAsDefault: 'BinaryString', |
95 |
on: {
|
96 |
loadend: _.bind(function(e, file) { |
97 |
this.input_key.val(e.target.result);
|
98 |
this.validate_form();
|
99 |
}, this),
|
100 |
error: function() {} |
101 |
} |
102 |
} |
103 |
FileReaderJS.setupInput(this.input_file.get(0), opts); |
104 |
}, |
105 |
|
106 |
validate_form: function() { |
107 |
this.form.find(".error").removeClass("error"); |
108 |
this.form.find(".errors").empty(); |
109 |
|
110 |
var name = _.trim(this.input_name.val()); |
111 |
var key = _.trim(this.input_key.val()); |
112 |
var error = false; |
113 |
|
114 |
if (!name) {
|
115 |
this.input_name.parent().addClass("error"); |
116 |
error = true;
|
117 |
} |
118 |
|
119 |
if (!key) {
|
120 |
this.input_key.parent().addClass("error"); |
121 |
error = true;
|
122 |
} else {
|
123 |
try {
|
124 |
key = snf.util.validatePublicKey(key); |
125 |
} catch (err) {
|
126 |
this.input_key.parent().addClass("error"); |
127 |
this.input_key.parent().find(".errors").append("<span class='error'>"+err+"</span>"); |
128 |
error = true;
|
129 |
} |
130 |
} |
131 |
|
132 |
if (error) { return false } |
133 |
return { key: key, name: name } |
134 |
}, |
135 |
|
136 |
_reset_form: function() { |
137 |
this.input_name.val(""); |
138 |
this.input_key.val(""); |
139 |
this.input_file.val(""); |
140 |
this.form.find(".error").removeClass("error"); |
141 |
this.form.find(".errors").empty(); |
142 |
this.form.show();
|
143 |
this.generate_msg.hide();
|
144 |
this.form_actions.show();
|
145 |
this.input_file.show();
|
146 |
this.close.hide();
|
147 |
this.error.hide();
|
148 |
this.model_actions.show();
|
149 |
}, |
150 |
|
151 |
beforeOpen: function() { |
152 |
this.private_key = undefined; |
153 |
this._reset_form();
|
154 |
this._init_reader();
|
155 |
this.unset_in_progress();
|
156 |
}, |
157 |
|
158 |
onOpen: function() { |
159 |
views.PublicKeyCreateView.__super__.onOpen.apply(this, arguments); |
160 |
this.input_name.focus();
|
161 |
}, |
162 |
|
163 |
init_handlers: function() { |
164 |
this.cancel.click(_.bind(function() { this.hide(); }, this)); |
165 |
this.close.click(_.bind(function() { this.hide(); }, this)); |
166 |
this.generate_action.click(_.bind(this.generate, this)); |
167 |
this.generate_download.click(_.bind(this.download_key, this)); |
168 |
this.form.submit(_.bind(function(e){ |
169 |
e.preventDefault(); |
170 |
this.submit_key(_.bind(function() { |
171 |
this.hide();
|
172 |
}, this))
|
173 |
}, this));
|
174 |
this.submit.click(_.bind(function() { |
175 |
this.form.submit();
|
176 |
}, this));
|
177 |
}, |
178 |
|
179 |
set_in_progress: function() { |
180 |
this.in_progress = true; |
181 |
this.submit.addClass("in-progress"); |
182 |
}, |
183 |
|
184 |
unset_in_progress: function() { |
185 |
this.in_progress = false; |
186 |
this.submit.removeClass("in-progress"); |
187 |
}, |
188 |
|
189 |
submit_key: function(cb) { |
190 |
var data = this.validate_form(); |
191 |
if (!data) { return } |
192 |
this.set_in_progress();
|
193 |
var params = {
|
194 |
complete: _.bind(function() { |
195 |
synnefo.storage.keys.fetch(); |
196 |
this.unset_in_progress();
|
197 |
cb && cb(); |
198 |
}, this)
|
199 |
}; |
200 |
|
201 |
synnefo.storage.keys.create({ |
202 |
content: data.key,
|
203 |
name: data.name,
|
204 |
}, params); |
205 |
}, |
206 |
|
207 |
download_key: function() { |
208 |
try {
|
209 |
var blob = new Blob([this.private_key], { |
210 |
type: "application/x-perm-key;charset=utf-8" |
211 |
}); |
212 |
saveAs(blob, "id_rsa");
|
213 |
} catch (err) {
|
214 |
alert(this.private_key);
|
215 |
} |
216 |
}, |
217 |
|
218 |
_generated_key_name: function() { |
219 |
if (this.input_name.val()) { |
220 |
return this.input_name.val(); |
221 |
} |
222 |
var name_tpl = "Generated ssh key name"; |
223 |
var name = name_tpl;
|
224 |
var exists = function() { |
225 |
return synnefo.storage.keys.filter(function(key){ |
226 |
return key.get("name") == name; |
227 |
}).length > 0;
|
228 |
} |
229 |
|
230 |
var count = 1; |
231 |
while(exists()) {
|
232 |
name = name_tpl + " {0}".format(++count);
|
233 |
} |
234 |
return name;
|
235 |
}, |
236 |
|
237 |
generate: function() { |
238 |
this.error.hide();
|
239 |
this.generate_msg.hide();
|
240 |
|
241 |
if (this.generating) { return } |
242 |
|
243 |
this.generating = true; |
244 |
this.generate_action.addClass("in-progress"); |
245 |
|
246 |
var success = _.bind(function(key) { |
247 |
this.generating = false; |
248 |
this.generate_action.removeClass("in-progress"); |
249 |
this.input_name.val(this._generated_key_name()); |
250 |
this.input_key.val(key.public); |
251 |
this.generate_msg.show();
|
252 |
this.private_key = key.private; |
253 |
this.form.hide();
|
254 |
this.form_actions.hide();
|
255 |
this.close.show();
|
256 |
this.model_actions.hide();
|
257 |
this.submit_key();
|
258 |
}, this);
|
259 |
var error = _.bind(function() { |
260 |
this.generating = false; |
261 |
this.generate_action.removeClass("in-progress"); |
262 |
this.private_key = undefined; |
263 |
this.show_error();
|
264 |
}, this);
|
265 |
var key = storage.keys.generate_new(success, error);
|
266 |
}, |
267 |
|
268 |
show_error: function(msg) { |
269 |
msg = msg === undefined ? "Something went wrong. Please try again later." : msg; |
270 |
if (msg) { this.error.find("p").html(msg) } |
271 |
this.error.show();
|
272 |
} |
273 |
}); |
274 |
|
275 |
views.PublicKeyView = views.ext.ModelView.extend({ |
276 |
tpl: '#public-key-view-tpl', |
277 |
post_init_element: function() { |
278 |
this.content = this.$(".content-cont"); |
279 |
this.content.hide();
|
280 |
this.content_toggler = this.$(".cont-toggler"); |
281 |
this.content_toggler.click(this.toggle_content); |
282 |
this.content_visible = false; |
283 |
}, |
284 |
|
285 |
toggle_content: function() { |
286 |
if (!this.content_visible) { |
287 |
this.content.slideDown(function() { |
288 |
$(window).trigger("resize"); |
289 |
}); |
290 |
this.content_visible = true; |
291 |
this.content_toggler.addClass("open"); |
292 |
} else {
|
293 |
this.content.slideUp(function() { |
294 |
$(window).trigger("resize"); |
295 |
}); |
296 |
this.content_visible = false; |
297 |
this.content_toggler.removeClass("open"); |
298 |
} |
299 |
}, |
300 |
|
301 |
remove_key: function() { |
302 |
this.model.do_remove();
|
303 |
}, |
304 |
|
305 |
post_hide: function() { |
306 |
views.PublicKeyView.__super__.post_hide.apply(this);
|
307 |
if (this.content_visible) { |
308 |
this.toggle_content();
|
309 |
this.content.hide();
|
310 |
} |
311 |
} |
312 |
}); |
313 |
|
314 |
views.PublicKeysCollectionView = views.ext.CollectionView.extend({ |
315 |
collection: storage.keys,
|
316 |
collection_name: 'keys', |
317 |
model_view_cls: views.PublicKeyView,
|
318 |
create_view_cls: views.PublicKeyCreateView,
|
319 |
initialize: function() { |
320 |
views.PublicKeysCollectionView.__super__.initialize.apply(this, arguments); |
321 |
this.collection.bind("add", _.bind(this.update_quota, this)); |
322 |
this.collection.bind("remove", _.bind(this.update_quota, this)); |
323 |
this.collection.bind("reset", _.bind(this.update_quota, this)); |
324 |
}, |
325 |
|
326 |
update_quota: function() { |
327 |
var quota = synnefo.config.userdata_keys_limit;
|
328 |
var available = quota - this.collection.length; |
329 |
if (available > 0) { |
330 |
this.create_button.removeClass("disabled"); |
331 |
this.create_button.attr("title", this.quota_limit_message || "Quota limit reached") |
332 |
} else {
|
333 |
this.create_button.addClass("disabled"); |
334 |
this.create_button.attr("title", ""); |
335 |
} |
336 |
} |
337 |
}); |
338 |
|
339 |
views.PublicKeysPaneView = views.ext.PaneView.extend({ |
340 |
id: "pane", |
341 |
el: '#public-keys-pane', |
342 |
collection_view_cls: views.PublicKeysCollectionView,
|
343 |
collection_view_selector: '#public-keys-list-view' |
344 |
}); |
345 |
|
346 |
})(this);
|
347 |
|