root/devel/lib/userlib.php

Revision 1564, 21.0 kB (checked in by misja, 9 months ago)

Misja Hoebe <misja@curverider.co.uk> Applied attachment:ticket:323:080227_user_friend_add_moderation.2.diff, closes #323

  • Property svn:eol-style set to native
Line 
1 <?php
2
3     /**
4      * Library of functions for user polling and manipulation.
5      *
6      * @copyright Copyright (C) 2004-2006 Ben Werdmuller and David Tosh
7      * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
8      * @package elgg
9      * @subpackage elgg.lib
10      */
11
12 // INITIALISATION //////////////////////////////////////////////////////////////
13
14     // TODO: These need somewhere else to live. They're to do with
15     // authentication and session management, not user management.
16
17     // Session variable name
18     define('user_session_name', 'elgguser');
19     
20     // Persistent login cookie DEFs
21     define('AUTH_COOKIE', 'elggperm');
22     define('AUTH_COOKIE_LENGTH', 31556926); // 1YR in seconds
23     
24     // Messages
25     define('AUTH_MSG_OK', __gettext("You have been logged on."));
26     define('AUTH_MSG_BADLOGIN', __gettext("Unrecognised username or password. The system could not log you on, or you may not have activated your account."));
27     define('AUTH_MSG_MISSING', __gettext("Either the username or password were not specified. The system could not log you on."));
28
29     /**
30      * User information value by id
31      *
32      * Returns a specified field by user id
33      *
34      * @param string $fieldname the specific field
35      * @param integer $user_id the user id
36      * @return mixed string if success else false if the user doesn't exist
37      * @author Ben WerdMuller <ben@curverider.co.uk>
38      */
39     function user_info($fieldname, $user_id) {
40         
41         // Name table
42         static $id_to_name_table;
43
44         // Returns field from a given ID
45
46         $user_id = (int) $user_id;
47         
48         if (!empty($user_id)) {
49             if (!isset($id_to_name_table[$user_id][$fieldname])) {
50                 //$id_to_name_table[$user_id][$fieldname] = get_field('users',$fieldname,'ident',$user_id);
51                 
52                 // this reduces number of db queries, but uses slightly more memory
53                 // due to adodb's recordset generation, it has both named and numeric array keys
54                 $id_to_name_table[$user_id] = (array) get_record('users','ident',$user_id);
55             }
56             if (isset($id_to_name_table[$user_id][$fieldname])) {
57                 return $id_to_name_table[$user_id][$fieldname];
58             }
59         }
60         
61         // If we've got here, the user didn't exist in the database
62         return false;
63         
64     }
65     
66     /**
67      * User information value by username
68      *
69      * Returns a specified field by username
70      *
71      * @param string $fieldname the specific field
72      * @param integer $user_id the user id
73      * @return mixed string if success else false if the user doesn't exist
74      * @author Ben WerdMuller <ben@curverider.co.uk>
75      */
76     function user_info_username($fieldname, $username) {
77         
78         // Name table
79         static $name_to_id_table;
80
81         // Returns user's ID from a given name
82         
83         if (!empty($username)) {
84             if (!isset($name_to_id_table[$username][$fieldname])) {
85                 //$name_to_id_table[$username][$fieldname] = get_field('users',$fieldname,'username',$username);
86                 $name_to_id_table[$username] = (array) get_record('users','username',$username);
87             }
88             if (isset($name_to_id_table[$username][$fieldname])){
89                 return $name_to_id_table[$username][$fieldname];
90             }
91         }
92         
93         // If we've got here, the user didn't exist in the database
94         return false;
95         
96     }
97     
98     /**
99      * Gets the type of a particular user
100      *
101      * @param integer $user_id the user id
102      * @return mixed string the user type or false if the user doesn't exist
103      * @author Ben WerdMuller <ben@curverider.co.uk>
104      */
105     function user_type($user_id) {
106         return user_info('user_type', $user_id);
107     }
108     
109     /**
110      * Returns a user's name, with event hooks allowing for interception.
111      * Internally passes around a "user_name" "display" event, with an object
112      * containing the elements 'name' and 'owner'.
113      *
114      * @uses $CFG
115      * @param integer $user_id  The unique ID of the user we want to find the name for.
116      * @return string Returns the user's name, or a blank string if something went wrong (eg the user didn't exist).
117      * @author Ben WerdMuller <ben@curverider.co.uk>
118      */
119     function user_name($user_id) {
120         global $CFG;
121         $user_name = new stdClass;
122         $user_name->owner = $user_id;
123         if ($user_name->name = user_info("name",$user_id)) {
124             if ($user_name = plugin_hook("user_name","display",$user_name)) {
125                 return $user_name->name;
126             }
127         }
128         return "";
129     }
130     
131     /**
132      * Returns the HTML to display a user's icon, with event hooks allowing for interception.
133      * Internally passes around a "user_icon" "display" event, with an object
134      * containing the elements 'html', 'icon' (being the icon ID), 'size', 'owner' and 'url'.
135      *
136      * @todo TODO refactor, separate display code
137      * @global CFG global configuration
138      * @param integer $user_id  The unique ID of the user we want to display the icon for.
139      * @param integer $size  The size of the icon we want to display (max: 100).
140      * @param boolean $urlonly  If true, returns the URL of the icon rather than the full HTML.
141      * @return string Returns the icon HTML, or the default icon if something went wrong (eg the user didn't exist).
142      * @author Ben WerdMuller <ben@curverider.co.uk>
143      */
144     function user_icon_html($user_id, $size = 100, $urlonly = false) {
145         global $CFG;
146         $extra = "";
147         $user_icon = new stdClass;
148         $user_icon->owner = $user_id;
149         $user_icon->size = $size;
150         if ($size < 100) {
151             $extra = "/h/$size/w/$size";
152         }
153         if ($user_icon->icon = user_info("icon",$user_id)) {
154             $user_icon->url = "{$CFG->wwwroot}_icon/user/{$user_icon->icon}{$extra}";
155         $user_fullname = user_info("name",$user_id);
156         $user_icon->html = "<img src=\"{$user_icon->url}\" border=\"0\" alt=\"{$user_fullname}\" title=\"{$user_fullname}\" />";
157             if ($user_icon = plugin_hook("user_icon","display",$user_icon)) {
158                 if ($urlonly) {
159                     return $user_icon->url;
160                 } else {
161                     return $user_icon->html;
162                 }
163             }
164         }
165         if ($urlonly) {
166             return -1;
167         } else {
168             return "<img src=\"{$CFG->wwwroot}_icon/user/-1{$extra}\" border=\"0\" alt=\"default user icon\" />";
169         }
170     }
171     
172 // USER FLAGS //////////////////////////////////////////////////////////////////
173
174     // Gets the value of a flag
175     function user_flag_get($flag_name, $user_id) {
176         if ($result = get_record('user_flags','flag',$flag_name,'user_id',$user_id)) {
177             return $result->value;
178         }
179         return false;
180     }
181     
182     // Removes a flag
183     function user_flag_unset($flag_name, $user_id) {
184         return delete_records('user_flags','flag',$flag_name,'user_id',$user_id);
185     }
186     
187     // Adds a flag
188     function user_flag_set($flag_name, $value, $user_id) {
189         $flag_name = trim($flag_name);
190         if ($flag_name) {
191             // Unset the flag first
192             user_flag_unset($flag_name, $user_id);
193             
194             // Then add data
195             $flag = new StdClass;
196             $flag->flag = $flag_name;
197             $flag->user_id = $user_id;
198             $flag->value = $value;
199             return insert_record('user_flags',$flag);
200         }
201     }
202     
203 // ACCESS RESTRICTIONS /////////////////////////////////////////////////////////
204
205     // Get current access level
206     // Utterly deprecated (user levels no longer work like this), but kept
207     // alive for now.
208     function accesslevel($owner = -1) {
209         $currentaccess = 0;
210
211         // For now, there are three access levels: 0 (logged out), 1 (logged in) and 1000 (me)
212         if (logged_on == 1) {
213             $currentaccess++;
214         }
215             
216         if ($_SESSION['userid'] == $owner) {
217             $currentaccess += 1000;
218         }
219         //error_log($currentaccess);
220             
221         return $currentaccess;
222     }
223     
224     // Protect users to a certain access level
225     function protect($level, $owner = -1) {
226         global $CFG;
227         
228         //error_log($level);
229         //error_log($owner);
230         if (accesslevel($owner) < $level) {
231             echo '<a href="' . $CFG->wwwroot . '">' . __gettext("Access Denied") . '</a>';
232             exit();
233         }
234     }
235
236 // NOTIFICATIONS AND MESSAGING /////////////////////////////////////////////////
237
238     //
239     
240     /**
241      * Send a message to a user
242      *
243      * @param integer $to the receiving user id
244      * @param integer $from the sending user id
245      * @param string $message the message body
246      * @return boolean
247      * @author Ben WerdMuller <ben@curverider.co.uk>
248      * @author Misja Hoebe <misja@curverider.co.uk>
249      */
250     function message_user($to, $from, $title, $message) {
251         
252        global $messages, $CFG;
253         
254         if (isset($to->ident)) {
255             $to = $to->ident;
256         }
257         
258         $notifications = user_flag_get("emailnotifications",$to);
259         if ($notifications) {
260             $email_from = new StdClass;
261             $email_from->email = $CFG->noreplyaddress;
262             $email_from->name = $CFG->sitename;
263
264             if ($email_to = get_record('users', 'ident', $to))
265             {
266                 if (!email_to_user($email_to,$email_from,$title,$message . "\n\n\n" . __gettext("You cannot reply to this message by email."))) {
267                     $messages[] = __gettext("Failed to send email. An unknown error occurred.");
268                 }
269             }
270         }
271         
272         $m = new StdClass;
273         $m->title = $title;
274         $m->body = $message;
275         $m->from_id = $from;
276         $m->to_id = $to;
277         $m->posted = time();
278         $m->status = 'unread';
279         
280         if (!insert_record('messages',$m)) {
281             trigger_error(__FUNCTION__.": Failed to send message from $from to $to. An unknown error occurred.", E_ERROR);
282             
283             $messages[] = __gettext("Failed to send message. An unknown error occurred.");
284         } else {
285             plugin_hook("message", "publish", $m);
286             return true;
287         }
288         
289     }
290     
291     /**
292      * Get user's messages
293      *
294      * Get the user's messages, optionally limit the number or the timeframe
295      *
296      * @param integer $user_id the user id
297      * @param integer $number the number of messages to retrieve
298      * @param integer $timeframe the timeframe
299      * @return mixed an ADODB RecordSet object with the results or false
300      * @author Ben WerdMuller <ben@curverider.co.uk>
301      */
302     function get_messages($user_id, $number = null, $timeframe = null) {
303         
304         global $CFG;
305         
306         $where = "";
307         $limit = "";
308         if ($number != null) {
309             $limit = "limit $number";
310         }
311         if ($timeframe != null) {
312             $where = " and posted > ". (time() - $timeframe);
313         }
314         
315         return get_records_sql("select * from ".$CFG->prefix."messages where to_id = $user_id $where order by posted desc $limit");
316         
317     }
318     
319     /**
320      * Return the basic HTML for a message (given its database row),
321      * where the title is a heading 2 and the body is in a paragraph.
322      *
323      * @param string $message the message body
324      * @return string HTML output
325      * @todo TODO refactor, separate display and logic
326      * @author Ben WerdMuller <ben@curverider.co.uk>
327      */   
328     function display_message($message) {
329         
330         global $CFG;
331         
332         if ($message->from_id == -1) {
333             $from->name = __gettext("System");
334         } else {
335             $from = get_record_sql("select * from ".$CFG->prefix."users where ident = " . $message->from_id);
336         }
337         
338         $title ="[" __gettext("Message from ");
339         if ($message->from_id != -1) {
340             $title .= "<a href=\"" . $CFG->wwwroot . user_info("username",$message->from_id) . "/\">";
341         }
342         $title .= $from->name;
343         if ($message->from_id != -1) {
344             $title .= "</a>";
345         }
346         $title .= "] " . $message->title;
347         $body = "<p>" . nl2br(str_replace("\t","&nbsp;&nbsp;&nbsp;&nbsp;",activate_urls($message->body))) . "</p>";
348         
349         $body = templates_draw(array(
350                                         'context' => 'databox1',
351                                         'name' => $title,
352                                         'column1' => $body
353                                       )
354                                 );
355         
356         return $body;
357         
358     }
359     
360     /**
361      * Send a notification to a user
362      *
363      * Could be a notifications or email,
364      * depending on a user's preferences
365      *
366      * @param integer $user_id the user id
367      * @param string $title the message title
368      * @param string $message the message body
369      * @return boolean
370      * @todo TODO fix return type
371      * @author Ben WerdMuller <ben@curverider.co.uk>
372      */   
373     function notify_user($user_id, $title, $message) {
374         
375         message_user($user_id, -1, $title, $message);
376     }
377     
378     /**
379      * Mark a user's messages as read
380      *
381      * @param integer $user_id the user's id
382      * @return mixed An ADODB RecordSet object with the results from the SQL call or false.
383      * @author Ben WerdMuller <ben@curverider.co.uk>
384      */
385     function messages_read($user_id) {
386         
387         global $CFG;
388
389         $result = set_field('messages', 'status', 'read', 'to_id', $user_id);
390         
391         return $result;
392     }
393     
394     /**
395      * Clean up user messages
396      *
397      * @global CFG global configuration
398      * @param integer $older_than
399      * @return boolean
400      * @todo TODO this should be relatively temporary (Ben?)
401      * @author Ben WerdMuller <ben@curverider.co.uk>
402      * @author Misja Hoebe <misja@curverider.co.uk>
403      */
404     function cleanup_messages($older_than) {
405     
406         global $CFG;
407         
408         $result = execute_sql("delete from ".$CFG->prefix."messages where posted < " . $older_than,false);
409         
410         return $result;
411     }
412     
413 // STATISTICS //////////////////////////////////////////////////////////////////
414
415     /**
416      * Count number of users
417      *
418      * @global CFG global configuration
419      * @param string $type the user_type (eg 'person')
420      * @param integer $last_action the minimum last time they performed an action
421      * @return integer the number of users
422      * @author Ben WerdMuller <ben@curverider.co.uk>
423      */
424     function count_users($type = '', $last_action = 0) {
425         
426         global $CFG;
427         
428         $where = "1 = 1";
429         if (!empty($type)) {
430             $where .= " AND user_type = '$type'";
431         }
432         if ($last_action > 0) {
433             $where .= " AND last_action > " . $last_action;
434         }
435         if ($users = get_records_sql('SELECT user_type, count(ident) AS numusers
436                                   FROM '.$CFG->prefix.'users
437                                   WHERE '.$where.'
438                                   GROUP BY user_type')) {
439             if (empty($type) || sizeof($users) > 1) {
440                 return $users;
441             }
442             foreach($users as $user) {
443                 return $user->numusers;
444             }
445         }
446         
447         return false;
448     }
449
450 // USER DEATH //////////////////////////////////////////////////////////////////
451
452     /**
453      * Delete a user.
454      *
455      * @global CFG global configuration
456      * @param integer $user_id  The unique ID of the user to delete.
457      * @return true|false Returns true if the user was deleted; false otherwise.
458      * @author Ben WerdMuller <ben@curverider.co.uk>
459      */
460     function user_delete($user_id) {
461
462         global $CFG;
463
464         // Verify that the user exists
465         if ($user = get_record_sql("select * from {$CFG->prefix}users where ident = {$user_id}")) {
466             
467             // Call the event hook for all plugins to do their worst with the user's data
468             $user = plugin_hook("user","delete",$user);
469             
470             // If all went well ...
471             if (!empty($user)) {
472                 
473                 // Remove any icons and icon folders
474                 if ($icons = get_records_sql("select * from {$CFG->prefix}icons where owner = {$user->ident}")) {
475                     foreach($icons as $icon) {
476                         $filepath = $CFG->dataroot . "icons/" . substr($user->username,0,1) . "/" . $user->username . "/" . $icon->filename;
477                         @unlink($filepath);
478                     }
479                     @rmdir($filepath = $CFG->dataroot . "icons/" . substr($user->username,0,1) . "/" . $user->username . "/");
480                 }
481                 
482                 // Remove the user from the database!
483                 delete_records("users","ident",$user->ident);
484                 delete_records("user_flags","user_id",$user->ident);
485                 delete_records("messages","to_id",$user->ident);
486                 delete_records("messages","from_id",$user->ident);
487                 return true;
488
489             }
490             
491             return false;
492         }
493     }
494     
495     /**
496      * Get the user's friends
497      *
498      * @global CFG global configuration
499      * @param integer $user_id the user id
500      * @return mixed a result set packed in an array or empty
501      * @author Misja Hoebe <misja@curverider.co.uk>
502      */
503     function user_friends($user_id) {
504         global $CFG;
505         
506         $result = get_records_sql('SELECT f.friend AS user_id,u.name FROM '.$CFG->prefix.'friends f
507                                    JOIN '.$CFG->prefix.'users u ON u.ident = f.friend
508                                    WHERE f.owner = ? ORDER BY u.name', array($user_id));
509         
510         return $result;
511     }
512
513     /**
514      * Get the users who have marked this user as a friend (sorted by the friends latest activity)
515      *
516      * @global CFG global configuration
517      * @param integer $user_id the user id
518      * @return mixed a result set packed in an array or empty
519      * @author Misja Hoebe <misja@curverider.co.uk>
520      */
521     function user_friends_of($user_id) {
522         global $CFG;
523         
524         $result = get_records_sql('SELECT u.ident, u.username FROM '.$CFG->prefix.'friends f
525                                   JOIN '.$CFG->prefix.'users u ON u.ident = f.owner
526                                   WHERE friend = ? AND u.user_type = ? order by u.last_action desc', array($user_id, 'person'));
527         
528         return $result;
529     }
530     
531     /**
532      * Add the a user to a friends list
533      *
534      * @param integer $user_id the user id
535      * @param integer $friend_id the friend id
536      * @param boolean $moderate is this a moderated friendship request
537      * @param string  $type the type, used for being able to reuse functionality for communities
538      * @return boolean
539      * @author Misja Hoebe <misja@curverider.co.uk>
540      */
541     function user_friend_add($user_id, $friend_id, $moderation = false, $type = 'friendship') {
542         if (empty($user_id) || empty($friend_id)) {
543             trigger_error(__FUNCTION__.": invalid arguments (user id: $user_id, friend id: $friend_id)", E_ERROR);
544         }
545         
546         if (!record_exists('friends', 'owner', $user_id, 'friend', $friend_id)) {
547             $obj         = new StdClass;
548             $obj->owner  = $user_id;
549             $obj->friend = $friend_id;
550
551             // Type check
552             if ($type != 'friendship' || $type != 'membership') {
553                 trigger_error("user_friend_add(): only type 'friendship' or 'membership' is accepted but '$type' was passed.", E_ERROR);
554                 return false;
555    &nb