      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