1 //
  2 // The Antville Project
  3 // http://code.google.com/p/antville
  4 //
  5 // Copyright 2001-2007 by The Antville People
  6 //
  7 // Licensed under the Apache License, Version 2.0 (the ``License'');
  8 // you may not use this file except in compliance with the License.
  9 // You may obtain a copy of the License at
 10 //
 11 //    http://www.apache.org/licenses/LICENSE-2.0
 12 //
 13 // Unless required by applicable law or agreed to in writing, software
 14 // distributed under the License is distributed on an ``AS IS'' BASIS,
 15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16 // See the License for the specific language governing permissions and
 17 // limitations under the License.
 18 //
 19 // $Revision:3329 $
 20 // $LastChangedBy:piefke3000 $
 21 // $LastChangedDate:2007-09-14 15:18:09 +0200 (Fri, 14 Sep 2007) $
 22 // $URL$
 23 //
 24 
 25 /**
 26  * @fileOverview Defines the Members prototype.
 27  */
 28 
 29 markgettext("Members");
 30 markgettext("members");
 31 
 32 /**
 33  * @name Members
 34  * @constructor
 35  * @property {Membership[]} _children
 36  * @property {Membership[]} contributors
 37  * @property {Membership[]} managers
 38  * @property {Membership[]} owners
 39  * @property {Membership[]} subscribers
 40  * @extends HopObject
 41  */
 42 
 43 /**
 44  * 
 45  * @param {String} action
 46  * @returns {Boolean}
 47  */
 48 Members.prototype.getPermission = function(action) {
 49    switch (action) {
 50       case "login":
 51       case "logout":
 52       case "register":
 53       case "reset":
 54       case "salt.js":
 55       return true;
 56    }
 57       
 58    if (!this._parent.getPermission("main")) {
 59       return false;
 60    }
 61 
 62    switch (action) {
 63       case "edit":
 64       case "privileges":
 65       case "subscriptions":
 66       case "updated":
 67       return !!session.user;
 68       
 69       case ".":
 70       case "main":
 71       case "add":
 72       case "owners":
 73       case "managers":
 74       case "contributors":
 75       case "subscribers":
 76       return Membership.require(Membership.OWNER) ||
 77             User.require(User.PRIVILEGED);
 78    }
 79    return false;
 80 }
 81 
 82 Members.prototype.main_action = function() {
 83    res.data.title = gettext("Site Members");
 84    res.data.list = renderList(this, "$Membership#member", 
 85          10, req.queryParams.page);
 86    res.data.pager = renderPager(this, this.href(req.action), 
 87          10, req.queryParams.page);
 88    res.data.body = this.renderSkinAsString("$Members#main");
 89    res.handlers.site.renderSkin("Site#page");
 90    return;
 91 }
 92 
 93 Members.prototype.register_action = function() {
 94    if (req.postParams.register) {
 95       try {
 96          var title = res.handlers.site.title;
 97          var user = User.register(req.postParams);
 98          var membership = new Membership(user, Membership.SUBSCRIBER);
 99          this.add(membership);
100          membership.notify(req.action, user.email, 
101                gettext('[{0}] Welcome to {1}!', root.title, title));
102          res.message = gettext('Welcome to “{0}”, {1}. Have fun!',
103                title, user.name);
104          res.redirect(User.getLocation() || this._parent.href());
105       } catch (ex) {
106          res.message = ex;
107       }
108    }
109 
110    session.data.token = User.getSalt();
111    res.data.action = this.href(req.action);
112    res.data.title = gettext("Register");
113    res.data.body = this.renderSkinAsString("$Members#register");
114    this._parent.renderSkin("Site#page");
115    return;
116 }
117 
118 Members.prototype.reset_action = function() {
119    if (req.postParams.reset) {
120       try {
121          if (!req.postParams.name || !req.postParams.email) {
122             throw Error(gettext("Please enter a user name and e-mail address."));
123          }
124          var user = User.getByName(req.postParams.name);
125          if (!user || user.email !== req.postParams.email) {
126             throw Error(gettext("User name and e-mail address do not match."))
127          }
128          var token = User.getSalt();
129          user.metadata.set("resetToken", token);
130          sendMail(user.email, gettext("[{0}] Password reset confirmation", 
131                root.title), user.renderSkinAsString("$User#notify_reset", {
132                   href: this.href("reset"),
133                   token: token
134                }));
135          res.message = gettext("A confirmation mail was sent to your e-mail address.");
136          res.redirect(this._parent.href());
137       } catch(ex) {
138          res.message = ex;
139       }
140    } else if (req.data.user && req.data.token) {
141       var user = User.getById(req.data.user);
142       if (user) {
143          var token = user.metadata.get("resetToken");
144          if (token) {
145             session.login(user);
146             if (req.postParams.save) {
147                var password = req.postParams.password;
148                if (!password) {
149                   res.message = gettext("Please enter a new password.");
150                } else if (password !== req.postParams.passwordConfirm) {
151                   res.message = gettext("The passwords do not match.");
152                } else {
153                   user.hash = (password + user.salt).md5();
154                   user.metadata.remove("resetToken");
155                   res.message = gettext("Your password was changed.");
156                   res.redirect(this._parent.href());
157                }
158             }
159             res.data.title = gettext("Reset Password");
160             res.data.body = this.renderSkinAsString("$Members#password");
161             this._parent.renderSkin("Site#page");
162             return;
163          }
164       }
165       res.message = gettext("This URL is not valid for resetting your password.");
166       res.redirect(this.href(req.action));
167    }
168    res.data.action = this.href(req.action);
169    res.data.title = gettext("Request Password Reset");
170    res.data.body = this.renderSkinAsString("$Members#reset");
171    this._parent.renderSkin("Site#page");
172    return;
173 }
174 
175 Members.prototype.login_action = function() {
176    if (req.postParams.login) {
177       try {
178          var user = User.login(req.postParams);
179          res.message = gettext('Welcome to {0}, {1}. Have fun!',
180                res.handlers.site.getTitle(), user.name);
181          res.redirect(User.getLocation() || this._parent.href());
182       } catch (ex) {
183          res.message = ex;
184       }
185    }
186    session.data.token = User.getSalt();
187    res.data.action = this.href(req.action);
188    res.data.title = gettext("Login");
189    res.data.body = this.renderSkinAsString("$Members#login");
190    this._parent.renderSkin("Site#page");
191    return;
192 }
193 
194 Members.prototype.logout_action = function() {
195    if (session.user) {
196       res.message = gettext("Good bye, {0}! Looking forward to seeing you again!", 
197             session.user.name);
198       User.logout();
199    }
200    res.redirect(this._parent.href());
201    return;
202 }
203 
204 Members.prototype.edit_action = function() {
205    if (req.postParams.save) {
206       try {
207          session.user.update(req.postParams);
208          res.message = gettext("The changes were saved successfully.");
209          res.redirect(this._parent.href());
210       } catch (err) {
211          res.message = err.toString();
212       }
213    }
214 
215    session.data.token = User.getSalt();
216    session.data.salt = session.user.salt; // FIXME
217    res.data.title = gettext("User Profile");
218    res.data.body = session.user.renderSkinAsString("$User#edit");
219    this._parent.renderSkin("Site#page");
220    return;
221 }
222 
223 Members.prototype.salt_js_action = function() {
224    res.contentType = "text/javascript";
225    var user;
226    if (user = User.getByName(req.queryParams.user)) {
227       res.write((user.salt || String.EMPTY).toSource());
228    }
229    return;
230 }
231 
232 Members.prototype.owners_action = function() {
233    res.data.title = gettext("Site Owners");
234    res.data.list = renderList(this.owners, 
235          "$Membership#member", 10, req.queryParams.page);
236    res.data.pager = renderPager(this.owners, 
237          this.href(req.action), 10, req.queryParams.page);
238    res.data.body = this.renderSkinAsString("$Members#main");
239    res.handlers.site.renderSkin("Site#page");
240    return;
241 }
242 
243 Members.prototype.managers_action = function() {
244    res.data.title = gettext("Site Managers");
245    res.data.list = renderList(this.managers, 
246          "$Membership#member", 10, req.queryParams.page); 
247    res.data.pager = renderPager(this.managers, 
248          this.href(req.action), 10, req.queryParams.page);
249    res.data.body = this.renderSkinAsString("$Members#main");
250    res.handlers.site.renderSkin("Site#page");
251    return;
252 }
253 
254 Members.prototype.contributors_action = function() {
255    res.data.title = gettext("Site Contributors");
256    res.data.list = renderList(this.contributors, 
257          "$Membership#member", 10, req.queryParams.page);
258    res.data.pager = renderPager(this.contributors, 
259          this.href(req.action), 10, req.data.page);
260    res.data.body = this.renderSkinAsString("$Members#main");
261    res.handlers.site.renderSkin("Site#page");
262    return;
263 }
264 
265 Members.prototype.subscribers_action = function() {
266    res.data.title = gettext("Site Subscribers");
267    res.data.list = renderList(this.subscribers, 
268          "$Membership#member", 10, req.queryParams.page);
269    res.data.pager = renderPager(this.subscribers, 
270          this.href(req.action), 10, req.queryParams.page);
271    res.data.body = this.renderSkinAsString("$Members#main");
272    res.handlers.site.renderSkin("Site#page");
273    return;
274 }
275 
276 Members.prototype.updated_action = function() {
277    res.data.title = gettext("Updates");
278    res.data.list = session.user.renderSkinAsString("$User#sites");
279    res.data.body = session.user.renderSkinAsString("$User#subscriptions");
280    res.handlers.site.renderSkin("Site#page");
281    return;
282 }
283 
284 Members.prototype.privileges_action = function() {
285    var site = res.handlers.site;
286    res.data.title = gettext("Privileges");
287    res.data.list = renderList(session.user.memberships, function(item) {
288       res.handlers.subscription = item.site;
289       item.renderSkin("$Membership#subscription");
290       return;
291    });
292    res.handlers.site = site;
293    res.data.body = session.user.renderSkinAsString("$User#subscriptions");
294    res.handlers.site.renderSkin("Site#page");
295    return;
296 }
297 
298 Members.prototype.subscriptions_action = function() {
299    var site = res.handlers.site;
300    res.data.title = gettext("Subscriptions");
301    res.data.list = renderList(session.user.subscriptions, function(item) {
302       res.handlers.subscription = item.site;
303       item.renderSkin("$Membership#subscription");
304       return;
305    });
306    res.handlers.site = site;
307    res.data.body = session.user.renderSkinAsString("$User#subscriptions");
308    res.handlers.site.renderSkin("Site#page");
309    return;
310 }
311 
312 Members.prototype.add_action = function() {
313    if (req.postParams.term) {
314       try {
315          var result = this.search(req.postParams.term);
316          if (result.length < 1) {
317             res.message = gettext("No user found to add as member.");
318          } else {
319             if (result.length >= 100) {
320                res.message = gettext("Too many users found, displaying the first {0} matches only.", 
321                      result.length);
322             } else {
323                res.message = ngettext("One user found.", "{0} users found.", 
324                       result.length);
325             }
326             res.data.result = this.renderSkinAsString("$Members#results", result);
327          }
328       } catch (ex) {
329          res.message = ex;
330          app.log(ex);
331       }
332    } else if (req.postParams.add) {
333       try {
334          var membership = this.addMembership(req.postParams);
335          membership.notify(req.action, membership.creator.email,  
336                gettext('[{0}] Notification of membership change', root.title));
337          res.message = gettext("Successfully added {0} to the list of members.", 
338                req.postParams.name);
339          res.redirect(membership.href("edit"));
340       } catch (ex) {
341          res.message = ex;
342          app.log(ex);
343       }
344       res.redirect(this.href());
345    }
346    res.data.action = this.href(req.action);
347    res.data.title = gettext('Add Member');
348    res.data.body = this.renderSkinAsString("$Members#add");
349    res.handlers.site.renderSkin("Site#page");
350    return;
351 }
352 
353 /**
354  * 
355  * @param {String} searchString
356  * @returns {Object}
357  */
358 Members.prototype.search = function(searchString) {
359    var self = this;
360    var mode = "=";
361    if (searchString.contains("*")) {
362       searchString = searchString.replace(/\*/g, "%");
363       mode = "like";
364    }
365    var sql = new Sql;
366    sql.retrieve(Sql.MEMBERSEARCH, mode, searchString, 100);
367    var counter = 0, name;
368    res.push();
369    sql.traverse(function() {
370       // Check if the user is not already a member
371       if (!self.get(this.name)) {
372          self.renderSkin("$Members#result", {name: this.name});
373          counter += 1;
374       }
375    });
376    return {
377       result: res.pop(),
378       length: counter
379    };
380 }
381 
382 /**
383  * 
384  * @param {Object} data
385  * @returns {Membership}
386  */
387 Members.prototype.addMembership = function(data) {
388    var user = root.users.get(data.name);
389    if (!user) {
390       throw Error(gettext("Sorry, your input did not match any registered user."));
391    } else if (this.get(data.name)) {
392       throw Error(gettext("This user is already a member of this site."));
393    }
394    var membership = new Membership(user, Membership.SUBSCRIBER);
395    this.add(membership);
396    return membership;
397 }
398