]> gitweb @ CieloNegro.org - Rakka.git/blob - js/systemConfig.js
ef3a2e8da9a4054dab2b15e7589ef6d4673b5c9a
[Rakka.git] / js / systemConfig.js
1 (function () {
2
3     var identityDecoder = function (src) {
4         return src;
5     };
6
7     var identityEncoder = function (src) {
8         return src;
9     };
10
11     var mapDecoder = function (src) {
12         var map   = {};
13         var lines = src.split(/\n/);
14
15         $.each(lines, function () {
16             var m = this.match(/^(\S+)\s+(\S+)$/);
17
18             if (m) {
19                 map[ m[1] ] = m[2];
20             }
21         });
22
23         return map;
24     };
25
26     var mapEncoder = function (map) {
27         var lines = [];
28
29         $.each(map, function (key) {
30                    lines.push(key + " " + this);
31                });
32
33         return lines.join("\n");
34     };
35
36     var boolDecoder = function (src) {
37         return src == "*";
38     };
39
40     var boolEncoder = function (bool) {
41         return bool ? "*" : "";
42     };
43
44     var decoder_of = {
45         siteName   : identityDecoder,
46         baseURI    : identityDecoder,
47         defaultPage: identityDecoder,
48         styleSheet : identityDecoder,
49         languages  : mapDecoder,
50         globalLock : boolDecoder
51     };
52
53     var encoder_of = {
54         siteName   : identityEncoder,
55         baseURI    : identityEncoder,
56         defaultPage: identityEncoder,
57         styleSheet : identityEncoder,
58         languages  : mapEncoder,
59         globalLock : boolEncoder
60     };
61
62     var cachedConf = null;
63
64     var isValidBaseURI = function (str) {
65         parseUri.options.strictMode = true;
66         var uri = parseUri(str);
67
68         return (uri.protocol  != "" &&
69                 uri.authority != "" &&
70                 uri.path      != "" &&
71                 uri.path.match(/\/$/) &&
72                 uri.query     == "" &&
73                 uri.anchor    == "");
74     };
75
76      // FIXME: Don't let user to manipulate directly this structure.
77      // FIXME: Values may include spaces.
78     var isValidMap = function (src) {
79         return src.match(/^(?:\S+\s+\S+(?:\n\S+\s+\S+)*\n?)?$/) != null;
80     };
81
82     Rakka.getUserList = function () {
83         var users = [];
84
85         $.ajax({
86            type: "GET",
87            url: Rakka.baseURI + "users",
88            async: false,
89            beforeSend: function (req) {
90                Rakka.setAuthorization(req);
91            },
92            success: function (xml) {
93                $(xml).find("user").each(function () {
94                    users.push(this.getAttribute("id"));
95                });
96            },
97            error: function (req) {
98                throw new Error(req.status + " " + req.statusText);
99            }
100         });
101
102         return users;
103     };
104
105     Rakka.getSystemConfig = function () {
106         if (cachedConf != null) {
107             return cachedConf;
108         }
109
110         var conf = {};
111         cachedConf = conf;
112
113         $.ajax({
114             type   : "GET",
115             url    : Rakka.baseURI + "systemConfig",
116             async  : false,
117             success: function (xml) {
118                 $(xml).find("value").each(function () {
119                     var path    = this.getAttribute("path");
120                     var decoder = decoder_of[path];
121
122                     if (decoder == null) {
123                         throw new Error("unknown config path: " + path);
124                     }
125                     else {
126                         conf[path] = decoder($(this).text());
127                     }
128                 });
129             },
130             error  : function (req) {
131                 throw new Error(req.status + " " + req.statusText);
132             }
133         });
134
135         return conf;
136     };
137
138     var appendConfigPanel = function ($area) {
139         $area.append($.H1({}, "Configuration"));
140
141         var fldSiteName
142             = $.INPUT({type: "text"});
143
144         var fldBaseURI
145             = $.INPUT({type: "text"});
146
147         var fldDefaultPage
148             = $.INPUT({type: "text"});
149
150         var fldStyleSheet
151             = $.INPUT({type: "text"});
152
153         var fldLanguages
154             = $.TEXTAREA({});
155
156         var chkGlobalLock
157             = $.INPUT({type: "checkbox"});
158
159         var btnSave
160             = $.INPUT({type: "button", value: "Save changes"});
161
162         var btnRevert
163             = $.INPUT({type: "button", value: "Revert changes"});
164
165         var makeClean = function () {
166             $(btnSave).attr({disabled: "disabled"});
167             $(btnRevert).attr({disabled: "disabled"});
168         };
169
170         var updateConfig = function () {
171             var conf  = Rakka.getSystemConfig();
172
173             fldSiteName.value     = conf.siteName;
174             fldBaseURI.value      = conf.baseURI;
175             fldDefaultPage.value  = conf.defaultPage;
176             fldStyleSheet.value   = conf.styleSheet;
177             fldLanguages.value    = encoder_of.languages(conf.languages);
178             chkGlobalLock.checked = conf.globalLock;
179
180             makeClean();
181         };
182         updateConfig();
183
184         var validate = function () {
185             var isValid = (function () {
186                                if (!isValidBaseURI(fldBaseURI.value)) {
187                                    return false;
188                                }
189
190                                if (fldDefaultPage.value.match(Rakka.rePageName) == null) {
191                                    return false;
192                                }
193
194                                if (fldStyleSheet.value.match(Rakka.rePageName) == null) {
195                                    return false;
196                                }
197
198                                if (!isValidMap(fldLanguages.value)) {
199                                    return false;
200                                }
201
202                                return true;
203                            })();
204
205             $(btnSave).attr({disabled: (isValid ? "" : "disabled")});
206         };
207
208         var makeDirty = function () {
209             $(btnRevert).attr({disabled: ""});
210             validate();
211         };
212
213         $(btnSave).click(function () {
214             var NS  = "http://cielonegro.org/schema/Rakka/Config/1.0";
215             var doc = document.implementation.createDocument(NS, "systemConfig", null);
216             var sc  = doc.documentElement;
217
218             var mkValue = function (path, value) {
219                 var elem = doc.createElementNS(NS, "value");
220                 elem.setAttribute("path", path);
221                 elem.appendChild(doc.createTextNode(value));
222                 return elem;
223             };
224
225             sc.appendChild(mkValue("siteName"   , fldSiteName.value));
226             sc.appendChild(mkValue("baseURI"    , fldBaseURI.value));
227             sc.appendChild(mkValue("defaultPage", fldDefaultPage.value));
228             sc.appendChild(mkValue("styleSheet" , fldStyleSheet.value));
229             sc.appendChild(mkValue("languages"  , fldLanguages.value));
230             sc.appendChild(mkValue("globalLock" , encoder_of["globalLock"](chkGlobalLock.checked)));
231
232             Rakka.displayWaitingMessage("Submitting... please wait.");
233
234             var url = Rakka.baseURI + "systemConfig";
235             $.ajax({ type       : "PUT",
236                      url        : url,
237                      contentType: "text/xml",
238                      data       : doc,
239                      processData: false,
240                      beforeSend : function (req) {
241                          Rakka.setAuthorization(req);
242                      },
243                      success    : function () {
244                          cachedConf = null;
245                          Rakka.hideWaitingMessage();
246                          makeClean();
247                      },
248                      error      : function (req) {
249                          Rakka.hideWaitingMessage();
250
251                          // FIXME: better error handling
252                          var $area = Rakka.switchScreen();
253                          $area.text("Error: " + req.status + " " + req.statusText);
254                      }
255             });
256         });
257
258         $(btnRevert).click(function () {
259             if (window.confirm("Do you really want to discard changes?")) {
260                 updateConfig();
261             }
262         });
263
264         var configPanel
265             = $.TABLE({className: "pageEditor"},
266                       $.TBODY({},
267                               $.TR({},
268                                    $.TH({}, "Site name"),
269                                    $.TD({}, fldSiteName)),
270                               $.TR({},
271                                    $.TH({}, "Base URI"),
272                                    $.TD({}, fldBaseURI)),
273                               $.TR({},
274                                    $.TH({}, "Default page"),
275                                    $.TD({}, fldDefaultPage)),
276                               $.TR({},
277                                    $.TH({}, "Style sheet"),
278                                    $.TD({}, fldStyleSheet)),
279                               $.TR({},
280                                    $.TH({}, "Languages"),
281                                    $.TD({}, fldLanguages)),
282                               $.TR({},
283                                    $.TH({}, "Global lock"),
284                                    $.TD({},
285                                         $.LABEL({},
286                                                 chkGlobalLock,
287                                                 "Disallow guest users to edit pages."))),
288                               $.TR({},
289                                    $.TH({}),
290                                    $.TD({}, btnSave, btnRevert))));
291
292          $(fldSiteName)
293              .add(fldBaseURI)
294              .add(fldDefaultPage)
295              .add(fldStyleSheet)
296              .add(fldLanguages)
297              .keyup(makeDirty)
298              .change(makeDirty);
299
300          $area.append(configPanel);
301      };
302
303      var appendUsersPanel = function ($area) {
304          $area.append($.H2({}, "Users"));
305          $area.append($.H3({}, "Existing Users"));
306
307          var tbody = $.TBODY();
308
309          var usersPanel
310              = $.TABLE({className: "pageEditor"},
311                        $.THEAD({},
312                                $.TR({},
313                                     $.TH({}, "User ID"),
314                                     $.TH({}, "Change Password"),
315                                     $.TH({}, "Delete User"))),
316                        tbody);
317
318          var updateUserList = function () {
319              var users = Rakka.getUserList();
320
321              $(tbody).empty();
322
323              for (var i = 0; i < users.length; i++) {
324                  var pass1  = $.INPUT({type: "password"});
325                  var pass2  = $.INPUT({type: "password"});
326                  var change = $.INPUT({type: "button", value: "Change"});
327
328                  var chpass = $.TABLE({className: "pageEditor"},
329                                       $.TR({},
330                                            $.TD({}, pass1),
331                                            $.TD({rowSpan: 2}, change)),
332                                       $.TR({},
333                                            $.TD({}, pass2)));
334
335                  var delUser = $.INPUT({type: "button", value: "Delete"});
336
337                  var validatePassword = function () {
338                      var isValid = (function () {
339                                        if (pass1.value == "") {
340                                            return false;
341                                        }
342
343                                        if (pass1.value != pass2.value) {
344                                            return false;
345                                        }
346
347                                        return true;
348                                     })();
349                      $(change).attr({disabled: (isValid ? "" : "disabled")});
350                  };
351                  validatePassword();
352                  $(pass1)
353                      .add(pass2)
354                      .change(validatePassword)
355                      .keyup(validatePassword);
356
357                  $.each(users, function () {
358                      var id = users[i];
359                      var tr = $.TR({},
360                                    $.TD({}, id),
361                                    $.TD({}, chpass),
362                                    $.TD({}, delUser)
363                                   );
364                      tbody.appendChild(tr);
365                  });
366              }
367          };
368          updateUserList();
369
370          $area.append(usersPanel);
371
372          $area.append($.H3({}, "Add new user"));
373
374          var userID  = $.INPUT({type: "text"});
375          var pass1   = $.INPUT({type: "password"});
376          var pass2   = $.INPUT({type: "password"});
377          var addUser = $.INPUT({type: "button", value: "Add"});
378          var addUserPanel = $.TABLE({className: "pageEditor"},
379                                     $.TR({},
380                                          $.TH({}, "User ID"),
381                                          $.TD({}, userID)),
382                                     $.TR({},
383                                          $.TH({}, "Password"),
384                                          $.TD({}, pass1)),
385                                     $.TR({},
386                                          $.TH({}, "Password (retype)"),
387                                          $.TD({}, pass2)),
388                                     $.TR({},
389                                          $.TH({}),
390                                          $.TD({}, addUser)));
391
392          $area.append(addUserPanel);
393      };
394
395      Rakka.showConfigPanel = function () {
396          var $area = Rakka.switchScreen();
397
398          appendConfigPanel($area);
399          appendUsersPanel($area);
400      };
401
402      $(document).ready(function () {
403          $("input.configButton")
404              .click(function () {
405                         Rakka.showConfigPanel();
406                     });
407      });
408 })();