      1: <?php
      2:
      3: /**
      4:  *
      5:  * The main person/user class for the site
      6:  *
      7:  * @package alpha::model
      8:  * @since 1.0
      9:  * @author John Collins <dev@alphaframework.org>
     10:  * @version $Id: PersonObject.inc 1693 2013-12-09 23:33:24Z alphadevx $
     11:  * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
     12:  * @copyright Copyright (c) 2013, John Collins (founder of Alpha Framework).
     13:  * All rights reserved.
     14:  *
     15:  * <pre>
     16:  * Redistribution and use in source and binary forms, with or
     17:  * without modification, are permitted provided that the
     18:  * following conditions are met:
     19:  *
     20:  * * Redistributions of source code must retain the above
     21:  *   copyright notice, this list of conditions and the
     22:  *   following disclaimer.
     23:  * * Redistributions in binary form must reproduce the above
     24:  *   copyright notice, this list of conditions and the
     25:  *   following disclaimer in the documentation and/or other
     26:  *   materials provided with the distribution.
     27:  * * Neither the name of the Alpha Framework nor the names
     28:  *   of its contributors may be used to endorse or promote
     29:  *   products derived from this software without specific
     30:  *   prior written permission.
     31:  *
     32:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
     33:  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
     34:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     35:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     36:  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
     37:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     38:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     39:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     40:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     41:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     42:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     43:  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     44:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     45:  * </pre>
     46:  *
     47:  */
     48: class PersonObject extends AlphaDAO {
     49:     /**
     50:      * The forum display name of the person
     51:      *
     52:      * @var String
     53:      * @since 1.0
     54:      */
     55:     protected $displayName;
     56:
     57:     /**
     58:      * The email address for the person
     59:      *
     60:      * @var String
     61:      * @since 1.0
     62:      */
     63:     protected $email;
     64:
     65:     /**
     66:      * The password for the person
     67:      *
     68:      * @var String
     69:      * @since 1.0
     70:      */
     71:     protected $password;
     72:
     73:     /**
     74:      * A Relation containing all of the rights groups that this person belongs to
     75:      *
     76:      * @var Relation
     77:      * @since 1.0
     78:      */
     79:     protected $rights;
     80:
     81:     /**
     82:      * A Relation containing all of the actions carried out by this person
     83:      *
     84:      * @var Relation
     85:      * @since 1.2.2
     86:      */
     87:     protected $actions;
     88:
     89:     /**
     90:      * An array of data display labels for the class properties
     91:      *
     92:      * @var array
     93:      * @since 1.0
     94:      */
     95:     protected $dataLabels = array("OID"=>"Member ID#",
     96:                                     "displayName"=>"Display Name",
     97:                                     "email"=>"E-mail Address",
     98:                                     "password"=>"Password",
     99:                                     "state"=>"Account state",
    100:                                     "URL"=>"Your site address",
    101:                                     "rights"=>"Rights Group Membership",
    102:                                     "actions"=>"Actions");
    103:
    104:     /**
    105:      * The name of the database table for the class
    106:      *
    107:      * @var string
    108:      * @since 1.0
    109:      */
    110:     const TABLE_NAME = 'Person';
    111:
    112:     /**
    113:      * The state of the person (account status)
    114:      *
    115:      * @var Enum
    116:      * @since 1.0
    117:      */
    118:     protected $state;
    119:
    120:     /**
    121:      * The website URL of the person
    122:      *
    123:      * @var String
    124:      * @since 1.0
    125:      */
    126:     protected $URL;
    127:
    128:     /**
    129:      * Trace logger
    130:      *
    131:      * @var Logger
    132:      * @since 1.0
    133:      */
    134:     private static $logger = null;
    135:
    136:     /**
    137:      * Constructor for the class that populates all of the complex types with default values
    138:      *
    139:      * @since 1.0
    140:      */
    141:     public function __construct() {
    142:         self::$logger = new Logger('PersonObject');
    143:         self::$logger->debug('>>__construct()');
    144:
    145:         // ensure to call the parent constructor
    146:         parent::__construct();
    147:         $this->displayName = new String();
    148:         $this->displayName->setRule(AlphaValidator::REQUIRED_USERNAME);
    149:         $this->displayName->setSize(70);
    150:         $this->displayName->setHelper('Please provide a name for display on the website (only letters, numbers, and .-_ characters are allowed!).');
    151:         $this->email = new String();
    152:         $this->email->setRule(AlphaValidator::REQUIRED_EMAIL);
    153:         $this->email->setSize(70);
    154:         $this->email->setHelper('Please provide a valid e-mail address as your username.');
    155:         $this->password = new String();
    156:         $this->password->setSize(70);
    157:         $this->password->setHelper('Please provide a password for logging in.');
    158:         $this->password->isPassword(true);
    159:         $this->state = new Enum(array(
    160:                                     'Active',
    161:                                     'Disabled'));
    162:         $this->state->setValue('Active');
    163:         $this->URL = new String();
    164:         $this->URL->setRule(AlphaValidator::OPTIONAL_HTTP_URL);
    165:         $this->URL->setHelper('URLs must be in the format http://some_domain/ or left blank!');
    166:         // add unique keys to displayName and email (which is effectively the username in Alpha)
    167:         $this->markUnique('displayName');
    168:         $this->markUnique('email');
    169:
    170:         $this->rights = new Relation();
    171:         $this->markTransient('rights');
    172:
    173:         $this->actions = new Relation();
    174:         $this->markTransient('actions');
    175:
    176:         $this->setupRels();
    177:
    178:         self::$logger->debug('<<__construct');
    179:     }
    180:
    181:     /**
    182:      * Set up the transient attributes for the rights group after it has loaded
    183:      *
    184:      * @since 1.0
    185:      */
    186:     protected function after_load_callback() {
    187:         $this->setupRels();
    188:     }
    189:
    190:     /**
    191:      * Set up the transient attributes for the site after it has loaded
    192:      *
    193:      * @since 1.0
    194:      */
    195:     protected function after_loadByAttribute_callback() {
    196:         $this->setupRels();
    197:     }
    198:
    199:     /**
    200:      * Looks up the OID for the Standard rights group, then relates the new person
    201:      * to that group if they are not in it already.  If that group does not exist it
    202:      * will be recreated!
    203:      *
    204:      * @since 1.0
    205:      */
    206:     protected function after_save_callback() {
    207:         if($this->getVersionNumber()->getValue() == 1) {
    208:             $standardGroup = new RightsObject();
    209:
    210:             $this->setupRels();
    211:
    212:             if(!$this->inGroup('Standard')) {
    213:                 try {
    214:                     $standardGroup->loadByAttribute('name', 'Standard');
    215:                 }catch (BONotFoundException $e) {
    216:                     $standardGroup->set('name', 'Standard');
    217:                     $standardGroup->save();
    218:                 }
    219:
    220:                 $lookup = $this->rights->getLookup();
    221:                 $lookup->setValue(array($this->getID(), $standardGroup->getID()));
    222:                 $lookup->save();
    223:             }
    224:         }
    225:     }
    226:
    227:     /**
    228:      * Encrypts any fields called 'password' posted for the PersonObject
    229:      *
    230:      * @since 1.0
    231:      */
    232:     protected function before_populateFromPost_callback() {
    233:         if(isset($_POST['password']) && preg_match(AlphaValidator::REQUIRED_STRING, $_POST['password']))
    234:             $_POST['password'] = crypt($_POST['password']);
    235:     }
    236:
    237:     /**
    238:      * Sets up the Relation definitions on this BO
    239:      *
    240:      * @since 1.0
    241:      */
    242:     protected function setupRels() {
    243:         // set up MANY-TO-MANY relation person2rights
    244:         if(isset($this->rights)) {
    245:             $this->rights->setRelatedClass('PersonObject', 'left');
    246:             $this->rights->setRelatedClassDisplayField('email', 'left');
    247:             $this->rights->setRelatedClass('RightsObject', 'right');
    248:             $this->rights->setRelatedClassDisplayField('name', 'right');
    249:             $this->rights->setRelationType('MANY-TO-MANY');
    250:             $this->rights->setValue($this->getID());
    251:         }
    252:
    253:         if(isset($this->actions)) {
    254:             $this->actions->setValue($this->OID);
    255:             $this->actions->setRelatedClass('ActionLogObject');
    256:             $this->actions->setRelatedClassField('created_by');
    257:             $this->actions->setRelatedClassDisplayField('message');
    258:             $this->actions->setRelationType('ONE-TO-MANY');
    259:         }
    260:     }
    261:
    262:     /**
    263:      * Setter for displayName
    264:      *
    265:      * @param string $displayName
    266:      * @since 1.0
    267:      */
    268:     public function setDisplayName($displayName) {
    269:         $this->displayName->setValue($displayName);
    270:     }
    271:
    272:     /**
    273:      * Getter for displayName
    274:      *
    275:      * @return String
    276:      * @since 1.0
    277:      */
    278:     public function getDisplayName() {
    279:         return $this->displayName;
    280:     }
    281:
    282:     /**
    283:      * Checks to see if the person is in the rights group specified
    284:      *
    285:      * @param string $groupName
    286:      * @return bool
    287:      * @since 1.0
    288:      */
    289:     public function inGroup($groupName) {
    290:         if(self::$logger == null)
    291:             self::$logger = new Logger('PersonObject');
    292:         self::$logger->debug('>>inGroup(groupName=['.$groupName.'])');
    293:
    294:         $group = new RightsObject();
    295:
    296:         try {
    297:             $group->loadByAttribute('name', $groupName);
    298:         }catch (BONotFoundException $e) {
    299:             self::$logger->error('Unable to load the group named ['.$groupName.']');
    300:             self::$logger->debug('<<inGroup [false]');
    301:             return false;
    302:         }
    303:
    304:         $rel = $group->getMembers();
    305:
    306:         try {
    307:             // load all person2rights RelationLookup objects for this person
    308:             $lookUps = $rel->getLookup()->loadAllByAttribute('leftID', $this->getID());
    309:             foreach($lookUps as $lookUp) {
    310:                 // the rightID (i.e. RightsObject OID) will be on the right side of the value array
    311:                 $ids = $lookUp->getValue();
    312:                 // if we have found a match, return true right away
    313:                 if($ids[1] == $group->getID()) {
    314:                     self::$logger->debug('<<inGroup [true]');
    315:                     return true;
    316:                 }
    317:             }
    318:         }catch (BONotFoundException $e) {
    319:             self::$logger->debug('<<inGroup [false]');
    320:             return false;
    321:         }
    322:
    323:         self::$logger->debug('<<inGroup [false]');
    324:         return false;
    325:     }
    326:
    327:     /**
    328:      * A generic method for mailing a person
    329:      *
    330:      * @param string $message
    331:      * @param string $subject
    332:      * @since 1.0
    333:      * @throws MailNotSentException
    334:      */
    335:     public function sendMail($message, $subject) {
    336:         global $config;
    337:
    338:         $body = '<html><head></head><body><p>Dear '.$this->getDisplayName().',</p>';
    339:
    340:         $body .= $message;
    341:
    342:         $body .= '</body></html>';
    343:
    344:         $headers = 'MIME-Version: 1.0'."\n";
    345:         $headers .= 'Content-type: text/html; charset=iso-8859-1'."\n";
    346:         $headers .= "From: ".$config->get('email.reply.to')."\n";
    347:
    348:         try {
    349:             mb_send_mail($this->get('email'), $subject, $body, $headers);
    350:         }catch (PHPException $e) {
    351:             throw new MailNotSentException('Error sending a mail to ['.$this->get('email').']');
    352:         }
    353:     }
    354:
    355:     /**
    356:      * Generates a random password for the user
    357:      *
    358:      * @return string
    359:      * @since 1.0
    360:      */
    361:     public function generatePassword() {
    362:         $alphabet = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z');
    363:         // the password will be 7 random characters and 2 numbers
    364:         $newPassword = '';
    365:         for ($i = 0; $i < 7; $i++) {
    366:             $newPassword.= $alphabet[rand(0,25)];
    367:         }
    368:         $newPassword.= rand(0,100);
    369:         $newPassword.= rand(0,100);
    370:
    371:         return $newPassword;
    372:     }
    373:
    374:     /**
    375:      * Method for getting a count of the amount of article comments posted by the user
    376:      *
    377:      * @return integer
    378:      * @since 1.0
    379:      * @throws AlphaException
    380:      */
    381:     public function getCommentCount() {
    382:         $temp = new ArticleCommentObject();
    383:
    384:         $sqlQuery = "SELECT COUNT(OID) AS post_count FROM ".$temp->getTableName()." WHERE created_by='".$this->OID."';";
    385:
    386:         $result = $this->query($sqlQuery);
    387:
    388:         if(!isset($result[0])) {
    389:             throw new AlphaException('Failed to get the count of the comments posted for the person ['.$this->getDisplayName().'], query is ['.$sqlQuery.']');
    390:             return 0;
    391:         }
    392:
    393:         $row = $result[0];
    394:
    395:         if(isset($row['post_count']))
    396:             return $row['post_count'];
    397:         else
    398:             return 0;
    399:     }
    400: }
    401:
    402: ?>