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