Statistics
| Branch: | Tag: | Revision:

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