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 /** 30 * @name Members 31 * @constructor 32 * @property {Membership[]} _children 33 * @property {Membership[]} contributors 34 * @property {Membership[]} managers 35 * @property {Membership[]} owners 36 * @property {Membership[]} subscribers 37 * @extends HopObject 38 */ 39 40 /** 41 * 42 * @param {String} action 43 * @returns {Boolean} 44 */ 45 Members.prototype.getPermission = function(action) { 46 switch (action) { 47 case "login": 48 case "logout": 49 case "register": 50 case "reset": 51 case "salt.js": 52 return true; 53 } 54 55 if (!this._parent.getPermission("main")) { 56 return false; 57 } 58 59 switch (action) { 60 case "edit": 61 case "privileges": 62 case "subscriptions": 63 case "updated": 64 return !!session.user; 65 66 case ".": 67 case "main": 68 case "add": 69 case "owners": 70 case "managers": 71 case "contributors": 72 case "subscribers": 73 return Membership.require(Membership.OWNER) || 74 User.require(User.PRIVILEGED); 75 } 76 return false; 77 } 78 79 Members.prototype.main_action = function() { 80 res.data.title = gettext("Members of {0}", this._parent.title); 81 res.data.list = renderList(this, "$Membership#member", 82 10, req.queryParams.page); 83 res.data.pager = renderPager(this, this.href(req.action), 84 10, req.queryParams.page); 85 res.data.body = this.renderSkinAsString("$Members#main"); 86 res.handlers.site.renderSkin("Site#page"); 87 return; 88 } 89 90 Members.prototype.register_action = function() { 91 if (req.postParams.register) { 92 try { 93 var title = res.handlers.site.title; 94 var user = User.register(req.postParams); 95 var membership = new Membership(user, Membership.SUBSCRIBER); 96 this.add(membership); 97 membership.notify(req.action, user.email, 98 gettext('Welcome to "{0}"!', title)); 99 res.message = gettext('Welcome to "{0}", {1}. Have fun!', 100 title, user.name); 101 res.redirect(User.getLocation() || this._parent.href()); 102 } catch (ex) { 103 res.message = ex; 104 } 105 } 106 107 session.data.token = User.getSalt(); 108 res.data.action = this.href(req.action); 109 res.data.title = gettext("Register"); 110 res.data.body = this.renderSkinAsString("$Members#register"); 111 this._parent.renderSkin("Site#page"); 112 return; 113 } 114 115 Members.prototype.reset_action = function() { 116 if (req.postParams.reset) { 117 try { 118 if (!req.postParams.name || !req.postParams.email) { 119 throw Error(gettext("Please enter a user name and e-mail address.")); 120 } 121 var user = User.getByName(req.postParams.name); 122 if (!user || user.email !== req.postParams.email) { 123 throw Error(gettext("User name and e-mail address do not match.")) 124 } 125 var token = User.getSalt(); 126 user.metadata.set("resetToken", token); 127 sendMail(root.email, user.email, 128 gettext("Confirmation for password reset at {0}", this._parent.title), 129 user.renderSkinAsString("$User#reset", { 130 href: this.href("reset"), 131 token: token 132 })); 133 res.message = gettext("A confirmation mail was sent to your e-mail address."); 134 res.redirect(this._parent.href()); 135 } catch(ex) { 136 res.message = ex; 137 } 138 } else if (req.data.user && req.data.token) { 139 var user = User.getById(req.data.user); 140 if (user) { 141 var token = user.metadata.get("resetToken"); 142 if (token) { 143 session.login(user); 144 if (req.postParams.save) { 145 var password = req.postParams.password; 146 if (!password) { 147 res.message = gettext("Please enter a new password."); 148 } else if (password !== req.postParams.passwordConfirm) { 149 res.message = gettext("The passwords do not match."); 150 } else { 151 user.hash = (password + user.salt).md5(); 152 user.metadata.remove("resetToken"); 153 res.message = gettext("Your password was changed."); 154 res.redirect(this._parent.href()); 155 } 156 } 157 res.data.title = gettext("Enter new password"); 158 res.data.body = this.renderSkinAsString("$Members#password"); 159 this._parent.renderSkin("Site#page"); 160 return; 161 } 162 } 163 res.message = gettext("This URL is not valid for resetting your password."); 164 res.redirect(this.href(req.action)); 165 } 166 res.data.action = this.href(req.action); 167 res.data.title = gettext("Reset password"); 168 res.data.body = this.renderSkinAsString("$Members#reset"); 169 this._parent.renderSkin("Site#page"); 170 return; 171 } 172 173 Members.prototype.login_action = function() { 174 if (req.postParams.login) { 175 try { 176 var user = User.login(req.postParams); 177 res.message = gettext('Welcome to "{0}", {1}. Have fun!', 178 res.handlers.site.getTitle(), user.name); 179 res.redirect(User.getLocation() || this._parent.href()); 180 } catch (ex) { 181 res.message = ex; 182 } 183 } 184 session.data.token = User.getSalt(); 185 res.data.action = this.href(req.action); 186 res.data.title = gettext("Login to {0}", this._parent.title); 187 res.data.body = this.renderSkinAsString("$Members#login"); 188 this._parent.renderSkin("Site#page"); 189 return; 190 } 191 192 Members.prototype.logout_action = function() { 193 if (session.user) { 194 res.message = gettext("Good bye, {0}! Lookin' forward to seeing you again!", 195 session.user.name); 196 User.logout(); 197 } 198 res.redirect(this._parent.href()); 199 return; 200 } 201 202 Members.prototype.edit_action = function() { 203 if (req.postParams.save) { 204 try { 205 session.user.update(req.postParams); 206 res.message = gettext("The changes were saved successfully."); 207 res.redirect(this._parent.href()); 208 } catch (err) { 209 res.message = err.toString(); 210 } 211 } 212 213 session.data.token = User.getSalt(); 214 session.data.salt = session.user.salt; // FIXME 215 res.data.title = gettext("Profile of user {0}", session.user.name); 216 res.data.body = session.user.renderSkinAsString("$User#edit"); 217 this._parent.renderSkin("Site#page"); 218 return; 219 } 220 221 Members.prototype.salt_js_action = function() { 222 res.contentType = "text/javascript"; 223 var user; 224 if (user = User.getByName(req.queryParams.user)) { 225 res.write((user.salt || String.EMPTY).toSource()); 226 } 227 return; 228 } 229 230 Members.prototype.owners_action = function() { 231 res.data.title = gettext("Owners of {0}", this._parent.title); 232 res.data.list = renderList(this.owners, 233 "$Membership#member", 10, req.queryParams.page); 234 res.data.pager = renderPager(this.owners, 235 this.href(req.action), 10, req.queryParams.page); 236 res.data.body = this.renderSkinAsString("$Members#main"); 237 res.handlers.site.renderSkin("Site#page"); 238 return; 239 } 240 241 Members.prototype.managers_action = function() { 242 res.data.title = gettext("Managers of {0}", this._parent.title); 243 res.data.list = renderList(this.managers, 244 "$Membership#member", 10, req.queryParams.page); 245 res.data.pager = renderPager(this.managers, 246 this.href(req.action), 10, req.queryParams.page); 247 res.data.body = this.renderSkinAsString("$Members#main"); 248 res.handlers.site.renderSkin("Site#page"); 249 return; 250 } 251 252 Members.prototype.contributors_action = function() { 253 res.data.title = gettext("Contributors of {0}", this._parent.title); 254 res.data.list = renderList(this.contributors, 255 "$Membership#member", 10, req.queryParams.page); 256 res.data.pager = renderPager(this.contributors, 257 this.href(req.action), 10, req.data.page); 258 res.data.body = this.renderSkinAsString("$Members#main"); 259 res.handlers.site.renderSkin("Site#page"); 260 return; 261 } 262 263 Members.prototype.subscribers_action = function() { 264 res.data.title = gettext("Subscribers of {0}", this._parent.title); 265 res.data.list = renderList(this.subscribers, 266 "$Membership#member", 10, req.queryParams.page); 267 res.data.pager = renderPager(this.subscribers, 268 this.href(req.action), 10, req.queryParams.page); 269 res.data.body = this.renderSkinAsString("$Members#main"); 270 res.handlers.site.renderSkin("Site#page"); 271 return; 272 } 273 274 Members.prototype.updated_action = function() { 275 res.data.title = gettext("Updated sites for user {0}", session.user.name); 276 res.data.list = session.user.renderSkinAsString("$User#sites"); 277 res.data.body = session.user.renderSkinAsString("$User#subscriptions"); 278 res.handlers.site.renderSkin("Site#page"); 279 return; 280 } 281 282 Members.prototype.privileges_action = function() { 283 var site = res.handlers.site; 284 res.data.title = gettext("Memberships of user {0}", session.user.name); 285 res.data.list = renderList(session.user.memberships, function(item) { 286 res.handlers.site = item.site; 287 item.renderSkin("$Membership#site"); 288 return; 289 }); 290 res.handlers.site = site; 291 res.data.body = session.user.renderSkinAsString("$User#subscriptions"); 292 res.handlers.site.renderSkin("Site#page"); 293 return; 294 } 295 296 Members.prototype.subscriptions_action = function() { 297 var site = res.handlers.site; 298 res.data.title = gettext("Subscriptions of user {0}", session.user.name); 299 res.data.list = renderList(session.user.subscriptions, function(item) { 300 res.handlers.site = item.site; 301 item.renderSkin("$Membership#site"); 302 return; 303 }); 304 res.handlers.site = site; 305 res.data.body = session.user.renderSkinAsString("$User#subscriptions"); 306 res.handlers.site.renderSkin("Site#page"); 307 return; 308 } 309 310 Members.prototype.add_action = function() { 311 if (req.postParams.term) { 312 try { 313 var result = this.search(req.postParams.term); 314 if (result.length < 1) { 315 res.message = gettext("Found no user matching the search input."); 316 } else { 317 if (result.length >= 100) { 318 res.message = gettext("Found too many users, displaying the first {0} matches only.", 319 result.length); 320 } else { 321 res.message = ngettext("Found one user matching the search input.", 322 "Found {0} users matching the search input.", 323 result.length); 324 } 325 res.data.result = this.renderSkinAsString("$Members#results", result); 326 } 327 } catch (ex) { 328 res.message = ex; 329 app.log(ex); 330 } 331 } else if (req.postParams.add) { 332 try { 333 res.handlers.sender = User.getMembership(); 334 var membership = this.addMembership(req.postParams); 335 membership.notify(req.action, membership.creator.email, 336 gettext('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 to site {0}', this._parent.title); 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 mode = "= '"; 360 if (searchString.contains("*")) { 361 searchString = searchString.replace(/\*/g, "%"); 362 mode = "like '"; 363 } 364 var dbConn = getDBConnection("antville"); 365 var query = "select name from user where name " + mode + searchString + 366 "' order by name asc"; 367 var rows = dbConn.executeRetrieval(query); 368 var counter = 0, name; 369 res.push(); 370 while (rows.next() && counter < 100) { 371 name = rows.getColumnItem("name"); 372 // Continue if the user is already a member 373 if (this.get(name)) { 374 continue; 375 }; 376 this.renderSkin("$Members#result", {name :name}); 377 counter += 1; 378 } 379 rows.release(); 380 return { 381 result: res.pop(), 382 length: counter 383 }; 384 } 385 386 /** 387 * 388 * @param {Object} data 389 * @returns {Membership} 390 */ 391 Members.prototype.addMembership = function(data) { 392 var user = root.users.get(data.name); 393 if (!user) { 394 throw Error(gettext("Sorry, your input did not match any registered user.")); 395 } else if (this.get(data.name)) { 396 throw Error(gettext("This user is already a member of this site.")); 397 } 398 var membership = new Membership(user, Membership.SUBSCRIBER); 399 this.add(membership); 400 return membership; 401 } 402 403 Members.prototype.modSorua_action = function() { 404 if (!app.data.modSorua) app.data.modSorua = new Array(); 405 var returnUrl = req.data["sorua-return-url"]; 406 var failUrl = req.data["sorua-fail-url"]; 407 var userID = req.data["sorua-user"]; 408 var action = req.data["sorua-action"]; 409 if (action == "authenticate") { // authenticate-action 410 if (session.user && (userID == null || userID == "" || session.user.name == userID)) { 411 // store returnUrl + timestamp + userID 412 app.data.modSorua[returnUrl] = {time: new Date(), userID: session.user.name}; 413 res.redirect(returnUrl); 414 } else if (failUrl) { 415 res.redirect(failUrl); 416 } else { 417 session.data.modSorua = {returnUrl: returnUrl, 418 userID: userID}; 419 res.redirect(this.href("modSoruaLoginForm")); 420 } 421 422 } else if (action == "verify") { 423 // first remove outdated entries 424 var now = new Date(); 425 var arr = new Array(); 426 for (var i in app.data.modSorua) { 427 if (app.data.modSorua[i] && app.data.modSorua[i].time && 428 now.valueOf() - app.data.modSorua[i].time.valueOf() < 1000 * 60) 429 arr[i] = app.data.modSorua[i]; 430 } 431 app.data.modSorua = arr; 432 // now check whether returnUrl has been used recently 433 if (app.data.modSorua[returnUrl]) { 434 res.status = 200; 435 res.write("user:" + app.data.modSorua[returnUrl].userID); 436 return; 437 } else { 438 res.status = 403; 439 return; 440 } 441 442 } else { // handle wrong call of AuthURI 443 res.redirect(root.href("main")); 444 445 } 446 } 447 448 Members.prototype.modSoruaLoginForm_action = function() { 449 if (!session.data.modSorua || !session.data.modSorua.returnUrl) 450 res.redirect(root.href()); // should not happen anyways 451 if (req.data.login) { 452 try { 453 res.message = this.evalLogin(req.data.name, req.data.password); 454 var returnUrl = session.data.modSorua.returnUrl; 455 app.data.modSorua[returnUrl] = {time: new Date(), userID: req.data.name}; 456 res.redirect(returnUrl); 457 } catch (err) { 458 res.message = err.toString(); 459 } 460 } 461 res.data.action = this.href("modSoruaLoginForm"); 462 this.renderSkin("modSorua"); 463 } 464