'_id'); /*protected $_schema = array('_id' => array('type' => 'id'), 'feed' => array('type'=>'string', 'array' => true), 'animelist' => array('type' => 'object', 'array' => true), 'mangalist' => array('type' => 'object', 'array' => true) );*/ public static function __init() { //Initialize the parent if you want the database and everything setup (which of course we do) parent::__init(); //Confirms that the username isn't already in use. Validator::add('isUniqUser', function($username) { //If we can't find a user with the same user name then the name is unique. return User::count(array('conditions' => compact('username'))) == 0; }); //Checks if the username contains profanity Validator::add('isClean', function($username) { //Needs to do a dictonary lookup, but too lazy to implement right now. return true; }); Validator::add('isValidGender', function($gender) { //If the geneder is male or female return true. return ($gender == 'Male' || $gender == 'Female'); }); Validator::add('isUniqueEmail', function($email) { //Find all the email address that match the one inputted, //If there is none found (count == 0) then return true (Email address is unique) return User::count(array('conditions' => compact('email'))) == 0; }); Validator::add('validBirthday', function($birthday) { // :TODO: //*birthday needs to be 1930 <= $birthday <= current year - 11 (11 or older); return true; }); } /* Validation code */ /* Things that need to be validated *The username cannot be taken *the username cannot cotain special chars or spaces *there must be an email address *The email address needs to be a valid email *it cannot be in use already *the password needs to be atleast 6 characters *the username cannot contain profanity *birthday needs to be 1930 <= $birthday <= current year - 11 (11 or older); *gender must be Male or Female */ public $validates = array( 'username' => array(array('isUniqUser', 'message' => "Username is already taken."), array('notEmpty', 'message' => 'Please enter a Username.'), array('isClean', 'message' => 'Profanity is not allowed in Usernames'), array('alphaNumeric', 'message' => "Usernames cant contain special characters") ), 'email' => array(array('email', 'message' => 'The email address is not valid.'), array('notEmpty', 'message' => 'An email address must be entered.'), array('isUniqueEmail', 'message' => 'That email address is already in use. Did you forget your password?') ) /*, 'newpass' => array(array('lengthBetween' => array('min' => '6', 'max' =>'20'), 'message' => 'Your password must be between 6 and 20 characters') )*/ /*, //It's always possible for people to submit invalid data using cURL or something. 'gender' => array('isValidGender', 'message' => 'Please check for dangly bits or lack thereof.') */ ); /* Defaults */ /* joindate = today, accesslevel = "user" */ public function updateuser($entity, $data) { $conditions = array('_id' => $entity->_id, 'state' => 'default'); $options = array('multiple' => false, 'safe' => true, 'upsert'=>true); return static::update($data, $conditions, $options); } /** * Creates a post and stores it into the appropriate user(s) array(s) * @param User $entity the instance of the user posting the message * @param Array $data The data from the request (usually submiited from the form) * @param Array $options Currently not implemented * @return null Nothing for now, though should return true or false in the future :TODO: */ public function post($entity, $data, array $options = array()) { //TODO, fix all methods so that they don't take $data directly //TODO add validators to these methods/models //Create the post $post = Post::create(array('datetime' => new MongoDate(), 'username' => $entity->username, 'user_id' => $entity->_id, 'level' => null)); //1. Parse //Break the string into an array of words $search = explode(" ", $data['body']); //if the first word is DM if ($search[0] == "DM") { //Remove the '@' symbol before we search for that username $to = substr($search[1], 1); $post->type = "DM"; //:TODO: Catch the return incase it's false. return $post->directMessage($to); } //If the post beings with a mention (it's a reply / note) if ($search[0] == "@") { //Set the post level to hidden $post->level = "hidden"; } //Check if there are any mentions or topics $post->body = $post->parse($search); //Because there is a chance that parse will set post level to something //We pass the current value to level since it will just //return the same it not set. //Yes, we could use an if ! null but whatever. $post->level = $this->postLevel($entity, $post, $post->level); //Save the post to the posts database. $post->save(); //If the user has friends if (count($entity->friends) > 0) { //Save this posts to the feed of all the Users Friends $post->storeAll($entity->friends); } //Add this post to the user's feed array $post->store($entity); //$save = $entity->save(null, array('validate' => false)); /* In the future, there should be a way to make this method quicker and non-blocking*/ //For each friend, post it in their feed (friends is an array of usernames as strings) /*if (!empty($entity->friends)) { foreach ($entity->friends as $friend) { //Grab the friend from the database $curFriend = User::find('first', array('conditions' => array('username' => $friend))); //Add the post to their feed. //Array unshift puts the new post at the first element of the feed array. $curFriend->feed = array_unshift($post->_id, $curFriend->feed); //Save the friend to the database, $curFriend->save(array('validates' => false)); //Eventually, we can call a node.js endpoint here //To tell all subscribers that there is a new a post //Something like "curl POST $post->_id nodeserver://endpoint/myFeed" } } */ } /** * Store's the post to the specified user's feed * @param User $user The user to add the post to * @param Post $post The post too add to the feed * @return boolean True if the operation sucsceeded, false otherwise */ private function storePost($user, $post) { $updateData = array('$push' => array('feed' => $post['_id']->__toString())); $conditions = array('_id' => $user['_id']); $result = User::update($updateData, $conditions, array('atomic' => false)); return $result; } /** * Returns the appropriate post level for the post * @see app\models\Post * @param User $user The user instance of the user that the post will be posted to * @param Post $post The Post to determine the level for * @param string $level The level (if you want to override the output) * @return string $level if one is passed in, otherwise hidden if the post begins with a mention or private if the user has his posts protected */ public static function postLevel($user, $post, $level = null) { //if for some crazy reason you need to set the post to a specific type using this // method then if $level is not null, return $level if ($level != null) { return $level; } //If the post is directed at user (begins with @username) //This is done in parse right now //return "hidden" //If the user has their post set to private if (isset($user->settings['private'])); { //return private return "private"; } //If none of the above apply return "public"; } //When we switch to a graph database, there is a bidirection vertex function //So we can cut this search down to one query, and one line of code :P /** * Check wether user1 and user2 are friends * * @param string $user1 The username of the first user * @param string $user2 The username of the second user * @return boolean True if the users are friends, false otherwise */ public static function areFriends($user1, $user2) { //Get the first user from the database, $usr1 = User::find('first', array('conditions' => array('username' => $user1))); //If user 2 is in user1's friends, if (in_array($user2, $usr1->friends)) { $usr2 = User::find('first', array('conditions' => array('username' => $user2))); //And user1 is in user2s friends if (in_array($user1, $usr2->friends)) { return true; } } //otherwise return false; } /** * GetPosts gets posts from the user (entity) based on some params, and returns them * @param User $entity, the calling object * @param Array $options, the options that will be used, you can see the defaults below * @return array(), with all the posts found or false, if somehow that didn't happen */ public function getPosts($entity, array $options = array()) { $posts; $defaults = array( 'limit' => '20', 'qualifier' => 'all', 'level' => 'public', ); //If the user passed in options if (!empty($options)) { //merge the options with the defaults (upsert them) array_merge($defaults, $options); } //var_dump($entity); //exit(); //If the user has more posts than the limit, return the limit, if the have less return $count = (count($entity->feed) >= $defaults['limit']) ? $defaults['limit'] : count($entity->feed); if ($count == 0) { return false; } //else var_dump(Post::find('all', array('conditions' => array('$in' => $entity->feed)))); exit(); for ($i = 0; $i < $count; $i++) { $posts[] = Post::find('all', array('conditions' => array('$in' => $entity->feed))); $posts[] = Post::find($qaulifier, array('conditions' => array('_id' => $entity->feed[$i], 'level' => $defaults[level]))); } return $posts; } /** * Increments the amount profile views for the user. * This is the command we are going to give to Mongo, which breaks down to db.users.update({_id : $id}, {$inc: {profileViews : 1}} ) * Which says, find the user by their mongo ID, then increment their profile views by one. * @param User $entity The instance of user to increment * @param string $type Not implemented but in the future will allow you to increment anime manga and kdrama list views :TODO: * @return null */ public function incrementViews($entity, $type = null) { if ($type = null) { $views = 'profileViews'; } $updateData = array('$inc' => array('profileViews' => 1)); $conditions = array('_id' => $entity['_id']); $result = User::update($updateData, $conditions, array('atomic' => false)); return $result; } //Overrides save so we can do some stuff before the data is commited to the database. public function save($entity, $data = null, array $options = array()) { //If the new password field is empty, or this is a new user if(!empty($entity->newpass) || !$entity->exists()) { //Generate Salt for the user. $salt = Password::salt('bf', 6); //Hash their password. $data['password'] = Password::hash($entity->newpass, $salt); $data['pepper'] = $salt; unset($entity->newpass); } //If the entity doesn't exist or if the password password has been modified return parent::save($entity, $data, $options); } } ?>