Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / static / snf / js / ui / web / ui_public_keys_view.js @ 9fd7a7a8

History | View | Annotate | Download (13 kB)

1
// Copyright 2011 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 api = snf.api = snf.api || {};
43
    var models = snf.models = snf.models || {}
44
    var storage = snf.storage = snf.storage || {};
45
    var ui = snf.ui = snf.ui || {};
46
    var util = snf.util = snf.util || {};
47

    
48
    var views = snf.views = snf.views || {}
49

    
50
    // shortcuts
51
    var bb = root.Backbone;
52
    
53
    views.PublicKeysView = views.CollectionView.extend({
54
        collection: storage.keys,
55

    
56
        confirm_delete_msg: 'Are you sure you want to remove this key ?',
57
        create_success_msg: 'Public key created successfully.',
58
        update_success_msg: 'Public key updated successfully.',
59
        create_failed_msg: 'Failed to create public key.',
60

    
61

    
62
        initialize: function(options) {
63
            views.PublicKeysView.__super__.initialize.apply(this, arguments);
64
            this.$(".private-cont").hide();
65
            _.bindAll(this);
66
            this.keys_limit = snf.config.userdata_keys_limit || 10000;
67
            this.bind("item:add", this.animate_on_add);
68
        },
69

    
70
        animate_on_add: function(list, el, model) {
71
            el.hide();
72
            el.fadeIn(400);
73
        },
74

    
75
        append_actions: function(el, model) {
76
            var actions = $('<div class="item-actions">' +
77
                            '<div class="item-action remove">remove</div>' + 
78
                            '<div class="item-action confirm-remove">' + 
79
                            '<span class="text do-confirm">confirm</span>' + 
80
                            '<span class="cancel-remove cancel">X</span></div>' + 
81
                            '<div class="item-action edit">edit</div>' + 
82
                            '<div class="item-action show">show key</div>' + 
83
                            '</div>');
84
            el.append(actions);
85
        },
86

    
87
        bind_list_item_actions: function(el, model) {
88
            views.PublicKeysView.__super__.bind_list_item_actions.apply(this, arguments);
89
            // initialize download link
90
            //snf.util.promptSaveFile(el.find(".item-actions .download"), model.get_filename(), model.get("content"))
91
        },
92
        
93
        close_private: function() {
94
            this.$(".private-cont").hide();
95
            this.$(".private-cont textarea").val("");   
96
            this.$('.private-cont [name=data]').val("");
97
            this.$('.private-cont [name=name]').val("");
98
        },
99

    
100
        init_handlers: function() {
101
            views.PublicKeysView.__super__.init_handlers.apply(this, arguments);
102
            
103
            this.$(".add-generate").click(_.bind(this.generate_new, this, undefined));
104

    
105
            // browser compat check
106
            if (snf.util.canReadFile()) {
107
                var self = this;
108
                this.form.find(".fromfile").get(0).addEventListener("change", function(e){
109
                    var f = undefined;
110
                    var files = e.target.files;
111
                    if (files.length == 0) { return };
112

    
113
                    f = files[0];
114
                    var data = snf.util.readFileContents(f, _.bind(function(data) {
115
                        this.form.find("textarea").val(data);   
116
                    }, self));
117
                });
118
            }
119

    
120
            var self = this;
121
            this.$(".private-cont .close-private").live("click", function(e) {
122
                self.close_private();
123
            });
124

    
125
            this.$(".item-action.show, .item-action.hide").live("click", function(e) {
126
                var open = $(this).parent().parent().parent().hasClass("expanded");
127
                if (open) {
128
                    $(this).text("show key");
129
                    $(this).addClass("show").removeClass("hide");
130
                } else {
131
                    $(this).text("hide key");
132
                    $(this).removeClass("show").addClass("hide");
133
                }
134
                $(this).parent().parent().parent().toggleClass("expanded");
135
            });
136
        },
137
        
138
        __save_new: function(generate_text, key) {
139
            var self = this;
140
            storage.keys.add_crypto_key(key.public,
141
                _.bind(function(instance, data) {
142
                    self.update_models();
143
                    this.generating = false;
144
                    this.$(".add-generate").text(generate_text).removeClass(
145
                        "in-progress").addClass("download");
146
                    this.show_download_private(instance.get('name'), key.private, instance);
147
                    this.enable_create();
148
                },this),
149

    
150
                _.bind(function() {
151
                    self.show_list_msg("error", "Cannot generate public key, please try again later.");
152
                    
153
                    this.generating = false;
154
                    this.download_private = false;
155

    
156
                    this.$(".add-generate").text(generate_text).removeClass("in-progress").removeClass("download");
157
                    this.enable_create();
158
                }, this)
159
            );
160
        },
161

    
162
        __generate_new: function(generate_text) {
163
            var self = this;
164
            var key = storage.keys.generate_new(_.bind(this.__save_new, this, generate_text), function(xhr){
165
                var resp_error = "";
166
                // try to parse response
167
                try {
168
                    json_resp = JSON.parse(xhr.responseText);
169
                    resp_error = json_resp.errors[json_resp.non_field_key].join("<br />");
170
                } catch (err) {}
171
                
172
                var msg = "Cannot generate new key pair";
173
                if (resp_error) {
174
                    msg += " ({0})".format(resp_error);
175
                }
176
                self.show_list_msg("error", msg);
177
                self.generating = false;
178
                self.download_private = false;
179
                self.$(".add-generate").text(generate_text).removeClass(
180
                        "in-progress").addClass("download");
181
                self.enable_create();
182
            });
183
        },
184

    
185
        generate_new: function() {
186
            if (this.generating) { return false };
187

    
188
            this.$(".private-cont").hide();
189
            this.generating = true;
190
            this.download_private = false;
191
            this.disable_create();
192
            var generate_text = this.$(".add-generate").text();
193
            this.$(".add-generate").text("Generating...").addClass("in-progress").removeClass("download");
194
            
195
            window.setTimeout(_.bind(this.__generate_new, this, generate_text), 400);
196

    
197
        },
198

    
199
        disable_create: function() {
200
            this.create_disabled = true;
201
            this.$(".collection-action.add").addClass("disabled");
202
        },
203
        
204
        enable_create: function() {
205
            this.create_disabled = false;
206
            this.$(".collection-action.add").removeClass("disabled");
207
        },
208
        
209
        show_download_private: function(name, private) {
210
            var download_cont = this.$(".private-cont");
211
            download_cont.show();
212
            download_cont.find(".key-contents textarea").val("");
213
            download_cont.find(".private-msg, .down-button").show();
214
            download_cont.find(".private-msg.copy").hide();
215
            download_cont.find(".private-msg.download").hide();
216
            download_cont.find("textarea").hide();
217
            download_cont.find("form").attr({action: snf.config.userdata_keys_url + '/download'})
218
            download_cont.find('[name=data]').val(private);
219
            download_cont.find('[name=name]').val(name);
220
        },
221

    
222
        update_list_item: function(el, model) {
223
            el.find(".name").text(model.get("name"));
224
            el.find(".key-type").text(model.identify_type() || "unknown");
225
            el.find(".publicid .param-content textarea").val(model.get("content"));
226
            el.find(".fingerprint .text").text(model.get("fingerprint"));
227
            el.find(".publicid").attr("title", _(model.get("content")).truncate(1000, "..."));
228
            return el;
229
        },
230

    
231
        update_list: function() {
232
            views.PublicKeysView.__super__.update_list.apply(this, arguments);
233
            this.check_limit();
234
        },
235

    
236
        check_limit: function() {
237
            if (snf.storage.keys.length >= this.keys_limit) {
238
                this.$(".collection-action").hide();
239
                this.$(".limit-msg").show();
240
            } else {
241
                this.$(".collection-action").show();
242
                this.$(".limit-msg").hide();
243
            }
244
        },
245

    
246
        update_form_from_model: function(model) {
247
            this.form.find("input.input-name").val(model.get("name"));
248
            this.form.find("textarea.input-content").val(model.get("content"));
249
        },
250

    
251
        get_form_data: function() {
252
            return {
253
                'name': this.form.find("input.input-name").val(),
254
                'content': this.form.find("textarea.input-content").val()
255
            }
256
        },
257
        
258
        get_fields_map: function() {
259
            return {'name': "input.input-name", 'content': "textarea.input-content"};
260
        },
261
        
262
        validate_data: function(data) {
263
            var user_data = _.clone(data)
264
            var errors = new snf.util.errorList();
265

    
266
            if (!data.name || _.clean(data.name) == "") {
267
                errors.add("name", "Provide a valid public key name");
268
            }
269

    
270
            if (!data.content || _.clean(data.content) == "") {
271
                errors.add("content", "Provide valid public key content");
272
                return errors;
273
            }
274
            
275
            try {
276
                var content = snf.util.validatePublicKey(data.content);
277
                if (content) {
278
                    this.form.find("textarea.input-content").val(content);
279
                }
280
            } catch (err) {
281
                errors.add("content", "Invalid key content (" + err + ")");
282
            }
283

    
284
            return errors;
285
        },
286

    
287
        reset: function() {
288
            this.$(".private-cont").hide();
289
            this.$(".list-messages").empty();
290
            this.$(".form-messages").empty();
291
            this.$(".model-item").removeClass("expanded");
292
            this.close_private();
293
            this.close_form();
294
        }
295

    
296
    })
297

    
298
    views.PublicKeysOverlay = views.Overlay.extend({
299
        
300
        view_id: "public_keys_view",
301
        content_selector: "#user_public_keys",
302
        css_class: 'overlay-public-keys overlay-info',
303
        overlay_id: "user_public_keys_overlay",
304

    
305
        title: "Manage your ssh keys",
306
        subtitle: "SSH keys",
307

    
308
        initialize: function(options) {
309
            views.PublicKeysOverlay.__super__.initialize.apply(this, arguments);
310
            this.subview = new views.PublicKeysView({el:this.$(".public-keys-view")});
311
            
312
            var self = this;
313
            this.$(".previous-view-link").live('click', function(){
314
                self.hide();
315
            })
316
        },
317

    
318
        show: function(view) {
319
            this.from_view = view || undefined;
320
            
321
            if (this.from_view) {
322
                this.$(".previous-view-link").show();
323
            } else {
324
                this.$(".previous-view-link").hide();
325
            }
326

    
327
            this.subview.reset();
328
            views.PublicKeysOverlay.__super__.show.apply(this, arguments);
329
        },
330
        
331
        onClose: function() {
332
            if (this.from_view) {
333
                this.hiding = true;
334
                this.from_view.skip_reset_on_next_open = true;
335
                this.from_view.show();
336
                this.from_view = undefined;
337
            }
338
        },
339

    
340
        init_handlers: function() {
341
        }
342
        
343
    });
344
})(this);
345

    
346