summaryrefslogtreecommitdiffstats
path: root/models/User.php
blob: cacda491fb942f2f158656aacfbae8260ea3b7b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
<?php 

namespace app\models;

use \MongoDate; 
use \lithium\util\String;
use \lithium\util\Validator;
use \App\Libraries\openID\LightOpenID;
use \lithium\security\Password;

class User extends \lithium\data\Model {

	public $hasMany = array('Post');

	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"
	*/
	

	/** 
	 * 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();
	}

	/**
	 * 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
		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);
	}
}

?>