diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 098156e8923..7cf0ffdeb82 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,10 @@ +Drupal x.x.x, xxxx-xx-xx +------------------------ + +- profile module: + * made it possible to administere profile fields. + * made it possible to browse the profiles by field. + Drupal 4.4.0, xxxx-xx-xx (release candidate) -------------------------------------------- diff --git a/database/database.mysql b/database/database.mysql index e5cdab7a3ac..10f3ff9dca2 100644 --- a/database/database.mysql +++ b/database/database.mysql @@ -282,13 +282,13 @@ CREATE TABLE node ( uid int(10) NOT NULL default '0', status int(4) NOT NULL default '1', created int(11) NOT NULL default '0', + changed int(11) NOT NULL default '0', comment int(2) NOT NULL default '0', promote int(2) NOT NULL default '0', moderate int(2) NOT NULL default '0', users longtext NOT NULL, teaser longtext NOT NULL, body longtext NOT NULL, - changed int(11) NOT NULL default '0', revisions longtext NOT NULL, static int(2) NOT NULL default '0', PRIMARY KEY (nid), @@ -312,6 +312,38 @@ CREATE TABLE page ( PRIMARY KEY (nid) ) TYPE=MyISAM; +-- +-- Table structure for table 'profile_fields' +-- + +CREATE TABLE profile_fields ( + fid int(10) NOT NULL auto_increment, + title varchar(255) default NULL, + name varchar(128) default NULL, + explanation TEXT default NULL, + category varchar(255) default NULL, + type varchar(128) default NULL, + weight tinyint(1) DEFAULT '0' NOT NULL, + overview tinyint(1) DEFAULT '0' NOT NULL, + options text, + KEY category (category), + UNIQUE KEY name (name), + PRIMARY KEY (fid) +); + +-- +-- Table structure for table 'profile_values' +-- + +CREATE TABLE profile_values ( + fid int(11) unsigned default '0', + uid int(11) unsigned default '0', + value text, + KEY uid (uid), + KEY fid (fid) +); + + -- -- Table structure for table 'url_alias' -- @@ -514,10 +546,12 @@ CREATE TABLE users ( threshold tinyint(1) default '0', theme varchar(255) NOT NULL default '', signature varchar(255) NOT NULL default '', - timestamp int(11) NOT NULL default '0', + created int(11) NOT NULL default '0', + changed int(11) NOT NULL default '0', status tinyint(4) NOT NULL default '0', timezone varchar(8) default NULL, language char(2) NOT NULL default '', + picture varchar(255) NOT NULL DEFAULT '', init varchar(64) default '', data longtext, rid int(10) unsigned NOT NULL default '0', diff --git a/database/database.pgsql b/database/database.pgsql index 12975aa294a..213f71a938d 100644 --- a/database/database.pgsql +++ b/database/database.pgsql @@ -511,10 +511,12 @@ CREATE TABLE users ( threshold smallint default '0', theme varchar(255) NOT NULL default '', signature varchar(255) NOT NULL default '', - timestamp integer NOT NULL default '0', + created integer NOT NULL default '0', + changed integer NOT NULL default '0', status smallint NOT NULL default '0', timezone varchar(8) default NULL, language char(2) NOT NULL default '', + picture varchar(255) NOT NULL DEFAULT '', init varchar(64) default '', data text default '', rid integer NOT NULL default '0', diff --git a/database/updates.inc b/database/updates.inc index e39267ef499..79b2573524e 100644 --- a/database/updates.inc +++ b/database/updates.inc @@ -50,7 +50,8 @@ $sql_updates = array( "2004-01-11" => "update_76", "2004-01-13" => "update_77", "2004-02-03" => "update_78", - "2004-02-21" => "update_79" + "2004-02-21" => "update_79", + "2004-03-11: first update since Drupal 4.4.0 release" => "update_80" ); function update_32() { @@ -760,6 +761,126 @@ function update_79() { return $ret; } +function update_80() { + + // Add a 'created' field to the users table: + update_sql('ALTER TABLE {users} ADD created INT(11) NOT NULL'); + update_sql('ALTER TABLE {users} CHANGE timestamp changed INT(11) NOT NULL'); + + // Add some indices to speed up the update process: + update_sql('ALTER TABLE {comments} ADD index (timestamp)'); + update_sql('ALTER TABLE {node} ADD index (created)'); + + // Assign everyone a created timestamp to begin with: + update_sql("UPDATE {users} SET created = changed WHERE created = ''"); + + // Print a status message:" + print '

Note: this might take a while ...

'; + + // Try updating the user records using the comment table: + $result = db_query('SELECT DISTINCT(u.uid) FROM {comments} c LEFT JOIN {users} u ON c.uid = u.uid WHERE c.timestamp < u.created'); + while ($account = db_fetch_object($result)) { + // Retrieve the proper timestamp: + $timestamp = db_result(db_query('SELECT MIN(timestamp) FROM {comments} WHERE uid = %d', $account->uid)); + + // Update this user record as well as older records with an older timestamp: + db_query('UPDATE {users} SET created = %d WHERE created > %d AND uid <= %d', $timestamp, $timestamp, $account->uid); + } + + // Try updating the user records using the node table: + $result = db_query('SELECT DISTINCT(u.uid) FROM {node} n LEFT JOIN {users} u ON n.uid = u.uid WHERE n.created < u.created'); + while ($account = db_fetch_object($result)) { + // Retrieve the proper timestamp: + $timestamp = db_result(db_query('SELECT MIN(created) FROM {node} WHERE uid = %d', $account->uid)); + + // Update this user record as well as older records with an older timestamp: + db_query('UPDATE {users} SET created = %d WHERE created > %d AND uid <= %d', $timestamp, $timestamp, $account->uid); + } + + // Add profile module related tables: + update_sql("CREATE TABLE {profile_fields} ( + fid int(10) NOT NULL auto_increment, + title varchar(255) default NULL, + name varchar(128) default NULL, + explanation TEXT default NULL, + category varchar(255) default NULL, + type varchar(128) default NULL, + weight tinyint(1) DEFAULT '0' NOT NULL, + overview tinyint(1) DEFAULT '0' NOT NULL, + options text, + KEY category (category), + UNIQUE KEY name (name), + PRIMARY KEY (fid) + );"); + + update_sql("CREATE TABLE {profile_values} ( + fid int(11) unsigned default '0', + uid int(11) unsigned default '0', + value text, + KEY uid (uid), + KEY fid (fid) + );"); + + // Migrate the old profile data to the new scheme: + $fields = array( + array("Name", "realname", "textfield", NULL, 0), + array("Address", "address", "textfield", NULL, 0), + array("City", "city", "textfield", NULL, 0), + array("State, province or region", "state", "textfield", NULL, 0), + array("Zip or postal code", "zip", "textfield", NULL, 0), + array("Country", "country", "textfield", NULL, 1), + array("Gender", "gender", "selection", "male\nfemale", 1), + array("Job title", "job", "textfield", NULL, 0), + array("ICQ messenger ID", "icq", "textfield", NULL, 0), + array("MSN messenger ID", "msn", "textfield", NULL, 0), + array("Yahoo messenger ID", "yahoo", "textfield", NULL, 0), + array("AIM messenger ID", "aim", "textfield", NULL, 0), + array("URL of homepage", "homepage", "textfield", NULL, 1), + array("Biography", "biography", "textarea", NULL, 0), + array("Interests", "interests", "textarea", NULL, 0), + array("Public key", "publickey", "textarea", NULL, 0) + ); + + // Remove existing data (debug mode): + db_query('DELETE FROM {profile_fields}'); + db_query('DELETE FROM {profile_values}'); + + foreach ($fields as $field) { + db_query("INSERT INTO {profile_fields} (title, name, type, category, options, overview) VALUES ('%s', '%s', '%s', 'Personal information', '%s', %d)", $field[0], $field[1], $field[2], $field[3], $field[4]); + } + db_query("ALTER TABLE {users} ADD picture varchar(255) NOT NULL DEFAULT ''"); + + $result = db_query("SELECT uid FROM {users}"); + while ($account = db_fetch_object($result)) { + // Load the user record: + $account = user_load(array('uid' => $account->uid)); + $edit = array(); + + // Modify the user record: + foreach ($fields as $field) { + $old = "profile_". $field[1]; + $new = $field[1]; + if ($account->$old) { + $edit[$new] = $account->$old; + } + unset($account->$old); + } + + // Gender specific changes: + if ($edit['gender'] == 'f') $edit['gender'] = 'female'; + if ($edit['gender'] == 'm') $edit['gender'] = 'male'; + + // Avatar specific changes: + if ($account->profile_avatar) { + $edit['picture'] = $account->profile_avatar; + } + unset($account->profile_avatar); + + // Save the update record: + user_save($account, $edit); + } +} + function update_sql($sql) { $edit = $_POST["edit"]; $result = db_query($sql); diff --git a/misc/drupal.css b/misc/drupal.css index 48112c3fabf..1b6fb965bc8 100644 --- a/misc/drupal.css +++ b/misc/drupal.css @@ -56,6 +56,7 @@ li a.active { padding: 0.25em 1em 0.25em 0em; } #pager { + clear: both; text-align: center; } #pager div { @@ -156,6 +157,14 @@ li a.active { .form-submit { margin: 0.5em 0; } +.profile { + clear: both; + margin: 1em 0em 1em 0em; +} +.profile .picture { + float: right; + margin: 0 1em 1em 0; +} #aggregator .feed img { float: right; } diff --git a/modules/blog.module b/modules/blog.module index e95937607dd..9b18115d4b5 100644 --- a/modules/blog.module +++ b/modules/blog.module @@ -37,12 +37,8 @@ function blog_access($op, $node) { } function blog_user($type, &$edit, &$user) { - switch ($type) { - case "view_public": - case "view_private": - if (user_access("maintain personal blog", $user)) { - return form_item(t("Blog"), l(t("view recent blog entries"), "blog/$user->uid", array("title" => t("Read %username's latest blog entries.", array("%username" => $user->name))))); - } + if ($type == 'view' && user_access("maintain personal blog", $user)) { + return form_item(t("Blog"), l(t("view recent blog entries"), "blog/$user->uid", array("title" => t("Read %username's latest blog entries.", array("%username" => $user->name))))); } } diff --git a/modules/blog/blog.module b/modules/blog/blog.module index e95937607dd..9b18115d4b5 100644 --- a/modules/blog/blog.module +++ b/modules/blog/blog.module @@ -37,12 +37,8 @@ function blog_access($op, $node) { } function blog_user($type, &$edit, &$user) { - switch ($type) { - case "view_public": - case "view_private": - if (user_access("maintain personal blog", $user)) { - return form_item(t("Blog"), l(t("view recent blog entries"), "blog/$user->uid", array("title" => t("Read %username's latest blog entries.", array("%username" => $user->name))))); - } + if ($type == 'view' && user_access("maintain personal blog", $user)) { + return form_item(t("Blog"), l(t("view recent blog entries"), "blog/$user->uid", array("title" => t("Read %username's latest blog entries.", array("%username" => $user->name))))); } } diff --git a/modules/comment.module b/modules/comment.module index 69fd729fb1a..a0225e44b0c 100644 --- a/modules/comment.module +++ b/modules/comment.module @@ -138,16 +138,15 @@ function comment_settings() { function comment_user($type, $edit, &$user) { switch ($type) { - case "view_public": - case "view_private": + case "view": if ($user->signature) { return form_item(t("Signature"), check_output($user->signature)); } break; - case "edit_form": + case "edit": // when user tries to edit his own data return array(t('Personal information') => form_textarea(t("Signature"), "signature", $user->signature, 70, 3, t("Your signature will be publicly displayed at the end of your comments.") ."
". filter_tips_short())); - case "edit_validate": + case "edit": // validate user data editing return array("signature" => $edit["signature"]); } @@ -203,7 +202,7 @@ function comment_reply($pid, $nid) { */ if ($pid) { - $comment = db_fetch_object(db_query("SELECT c.*, u.uid, u.name, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0", $pid)); + $comment = db_fetch_object(db_query("SELECT c.*, u.uid, u.name, u.picture, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0", $pid)); $comment = drupal_unpack($comment); $output .= theme("comment_view", $comment); } @@ -258,7 +257,7 @@ function comment_preview($edit) { $output .= theme("comment_form", $edit, t("Reply")); if ($edit["pid"]) { - $comment = db_fetch_object(db_query("SELECT c.*, u.uid, u.name, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0", $edit["pid"])); + $comment = db_fetch_object(db_query("SELECT c.*, u.uid, u.name, u.picture, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0", $edit["pid"])); $comment = drupal_unpack($comment); $output .= theme("comment_view", $comment); } @@ -559,7 +558,7 @@ function comment_render($node, $cid = 0) { $output .= "
\n"; $output .= form_hidden("nid", $nid); - $result = db_query("SELECT c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.data, c.score, c.users FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0 GROUP BY c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.data, c.score, c.users", $cid); + $result = db_query("SELECT c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.picture, u.data, c.score, c.users FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0 GROUP BY c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.picture, u.data, c.score, c.users", $cid); if ($comment = db_fetch_object($result)) { $output .= theme("comment_view", $comment, theme('links', module_invoke_all('link', 'comment', $comment, 1))); @@ -576,9 +575,9 @@ function comment_render($node, $cid = 0) { ** Multiple comments view */ - $query .= "SELECT c.cid as cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.data, c.score, c.users, c.thread FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.nid = '". check_query($nid) ."' AND c.status = 0"; + $query .= "SELECT c.cid as cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.picture, u.data, c.score, c.users, c.thread FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.nid = '". check_query($nid) ."' AND c.status = 0"; - $query .= " GROUP BY c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.data, c.score, c.users, c.thread"; + $query .= " GROUP BY c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.picture, u.data, c.score, c.users, c.thread"; /* ** We want to use the standard pager, but threads would need every diff --git a/modules/comment/comment.module b/modules/comment/comment.module index 69fd729fb1a..a0225e44b0c 100644 --- a/modules/comment/comment.module +++ b/modules/comment/comment.module @@ -138,16 +138,15 @@ function comment_settings() { function comment_user($type, $edit, &$user) { switch ($type) { - case "view_public": - case "view_private": + case "view": if ($user->signature) { return form_item(t("Signature"), check_output($user->signature)); } break; - case "edit_form": + case "edit": // when user tries to edit his own data return array(t('Personal information') => form_textarea(t("Signature"), "signature", $user->signature, 70, 3, t("Your signature will be publicly displayed at the end of your comments.") ."
". filter_tips_short())); - case "edit_validate": + case "edit": // validate user data editing return array("signature" => $edit["signature"]); } @@ -203,7 +202,7 @@ function comment_reply($pid, $nid) { */ if ($pid) { - $comment = db_fetch_object(db_query("SELECT c.*, u.uid, u.name, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0", $pid)); + $comment = db_fetch_object(db_query("SELECT c.*, u.uid, u.name, u.picture, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0", $pid)); $comment = drupal_unpack($comment); $output .= theme("comment_view", $comment); } @@ -258,7 +257,7 @@ function comment_preview($edit) { $output .= theme("comment_form", $edit, t("Reply")); if ($edit["pid"]) { - $comment = db_fetch_object(db_query("SELECT c.*, u.uid, u.name, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0", $edit["pid"])); + $comment = db_fetch_object(db_query("SELECT c.*, u.uid, u.name, u.picture, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0", $edit["pid"])); $comment = drupal_unpack($comment); $output .= theme("comment_view", $comment); } @@ -559,7 +558,7 @@ function comment_render($node, $cid = 0) { $output .= "
\n"; $output .= form_hidden("nid", $nid); - $result = db_query("SELECT c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.data, c.score, c.users FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0 GROUP BY c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.data, c.score, c.users", $cid); + $result = db_query("SELECT c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.picture, u.data, c.score, c.users FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0 GROUP BY c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.picture, u.data, c.score, c.users", $cid); if ($comment = db_fetch_object($result)) { $output .= theme("comment_view", $comment, theme('links', module_invoke_all('link', 'comment', $comment, 1))); @@ -576,9 +575,9 @@ function comment_render($node, $cid = 0) { ** Multiple comments view */ - $query .= "SELECT c.cid as cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.data, c.score, c.users, c.thread FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.nid = '". check_query($nid) ."' AND c.status = 0"; + $query .= "SELECT c.cid as cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.picture, u.data, c.score, c.users, c.thread FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.nid = '". check_query($nid) ."' AND c.status = 0"; - $query .= " GROUP BY c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.data, c.score, c.users, c.thread"; + $query .= " GROUP BY c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.picture, u.data, c.score, c.users, c.thread"; /* ** We want to use the standard pager, but threads would need every diff --git a/modules/drupal.module b/modules/drupal.module index 77a5c8f3a6f..b6392a501d4 100644 --- a/modules/drupal.module +++ b/modules/drupal.module @@ -185,22 +185,4 @@ function drupal_login($arguments) { } } -function drupal_user($type, $edit, $user) { - - $module = "drupal"; - $name = module_invoke($module, "info", "name"); - switch ($type) { - case "view_private": - $result = user_get_authname($user, $module); - $title = t("%name ID", array("%name" => $name)); - if ($result) { - return form_item($title, $result); - } - else { - // TODO: use a variation of $base_url instead of $HTTP_HOST below - return form_item($title, "$user->name@". $_SERVER["HTTP_HOST"]); - } - } -} - ?> diff --git a/modules/drupal/drupal.module b/modules/drupal/drupal.module index 77a5c8f3a6f..b6392a501d4 100644 --- a/modules/drupal/drupal.module +++ b/modules/drupal/drupal.module @@ -185,22 +185,4 @@ function drupal_login($arguments) { } } -function drupal_user($type, $edit, $user) { - - $module = "drupal"; - $name = module_invoke($module, "info", "name"); - switch ($type) { - case "view_private": - $result = user_get_authname($user, $module); - $title = t("%name ID", array("%name" => $name)); - if ($result) { - return form_item($title, $result); - } - else { - // TODO: use a variation of $base_url instead of $HTTP_HOST below - return form_item($title, "$user->name@". $_SERVER["HTTP_HOST"]); - } - } -} - ?> diff --git a/modules/locale.module b/modules/locale.module index eedba7595f6..907c99834f3 100644 --- a/modules/locale.module +++ b/modules/locale.module @@ -74,7 +74,7 @@ function locale_link($type) { function locale_user($type, &$edit, &$user) { global $languages; - if ($type == "edit_form" && count($languages) > 1) { + if ($type == 'edit' && count($languages) > 1) { return array(t('Locale settings') => form_radios(t("Language"), 'language', $user->language, $languages, t("Selecting a different language will change the language of the site."))); } } diff --git a/modules/locale/locale.module b/modules/locale/locale.module index eedba7595f6..907c99834f3 100644 --- a/modules/locale/locale.module +++ b/modules/locale/locale.module @@ -74,7 +74,7 @@ function locale_link($type) { function locale_user($type, &$edit, &$user) { global $languages; - if ($type == "edit_form" && count($languages) > 1) { + if ($type == 'edit' && count($languages) > 1) { return array(t('Locale settings') => form_radios(t("Language"), 'language', $user->language, $languages, t("Selecting a different language will change the language of the site."))); } } diff --git a/modules/node.module b/modules/node.module index 3e1a62155ae..16c7015d6b9 100644 --- a/modules/node.module +++ b/modules/node.module @@ -340,7 +340,7 @@ function node_load($conditions, $revision = -1) { ** Retrieve the node: */ - $node = db_fetch_object(db_query('SELECT n.*, u.uid, u.name, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid WHERE '. implode(' AND ', $cond))); + $node = db_fetch_object(db_query('SELECT n.*, u.uid, u.name, u.picture, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid WHERE '. implode(' AND ', $cond))); $node = drupal_unpack($node); /* diff --git a/modules/node/node.module b/modules/node/node.module index 3e1a62155ae..16c7015d6b9 100644 --- a/modules/node/node.module +++ b/modules/node/node.module @@ -340,7 +340,7 @@ function node_load($conditions, $revision = -1) { ** Retrieve the node: */ - $node = db_fetch_object(db_query('SELECT n.*, u.uid, u.name, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid WHERE '. implode(' AND ', $cond))); + $node = db_fetch_object(db_query('SELECT n.*, u.uid, u.name, u.picture, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid WHERE '. implode(' AND ', $cond))); $node = drupal_unpack($node); /* diff --git a/modules/profile.module b/modules/profile.module index a16c47c204f..d1e5e5f0c9a 100644 --- a/modules/profile.module +++ b/modules/profile.module @@ -1,306 +1,300 @@ array("textfield", t("Name"), "", 64, 64, ""), - "address" => array("textfield", t("Address"), "", 64, 64, ""), - "city" => array("textfield", t("City"), "", 64, 64, ""), - "state" => array("textfield", t("State, province or region"), "", 64, 64, ""), - "zip" => array("textfield", t("Zip or postal code"), "", 7, 10, ""), - "country" => array("textfield", t("Country"), "", 64, 64, ""), - "birthday" => array("", t("Birthday"), ""), - "gender" => array("select", t("Gender"), "", array(0 => "-", "m" => t("male"), "f" => t("female")), "", 0, 0), - "job" => array("textfield", t("Job title"), "", 64, 64, ""), - "icq" => array("textfield", t("ICQ messenger ID"), "", 12, 12, ""), - "msn" => array("textfield", t("MSN messenger ID"), "", 64, 64, ""), - "yahoo" => array("textfield", t("Yahoo messenger ID"), "", 64, 64, ""), - "aim" => array("textfield", t("AIM messenger ID"), "", 64, 64, ""), - "homepage" => array("textfield", t("URL of homepage"), "", 64, 64, t("Make sure you enter a fully qualified URL: remember to include \"http://\".")), - "biography" => array("textarea", t("Biography"), "", 64, 4, ""), - "interests" => array("textarea", t("Interests"), "", 64, 4, ""), - "publickey" => array("textarea", t("Public key"), "", 64, 4, ""), - "avatar" => array("", t("Avatar or picture"), t("Your virtual face or picture. Maximum dimensions are %dimensions and the maximum size is %size kB.", array("%dimensions" => variable_get("profile_avatar_dimensions", "85x85"), "%size" => variable_get("profile_avatar_file_size", "30")))) - ); - - $GLOBALS["profile_days"] = array_merge(array(0 => t("day")), drupal_map_assoc(range(1, 31))); - $GLOBALS["profile_months"] = array(0 => t("month"), 1 => t("January"), 2 => t("February"), 3 => t("March"), 4 => t("April"), 5 => t("May"), 6 => t("June"), 7 => t("July"), 8 => t("August"), 9 => t("September"), 10 => t("October"), 11 => t("November"), 12 => t("December")); -} +// TODO: add a 'date' field so we can migrate the birthday information. function profile_help($section) { - $output = ""; - switch ($section) { case 'admin/system/modules#description': $output = t("Support for configurable user profiles."); break; - case 'admin/system/modules/profile': - $output = t("When a user creates an account you can ask for some extra information, as well as letting the user have a small picture, called an avatar.
  • In order for a user to enter information, you must check enable.
  • In order for other people to see the entered information, you must make it public.
  • If an item is public, but not enabled, the user can never give it a value and it will never be seen. Public does not imply enable.
", array("%edit" => url("user/edit"))); - break; } return $output; + + +} + +function profile_link($type) { + if ($type == 'system') { + menu('profile', t('browse'), 'profile_browse', 0, MENU_HIDE); + + if (user_access('administer users')) { + menu('admin/system/modules/profile', t('profile'), 'profile_admin_overview'); + menu('admin/system/modules/profile/add', NULL, 'profile_admin_add', 0, MENU_HIDE); + menu('admin/system/modules/profile/edit', NULL, 'profile_admin_edit', 0, MENU_HIDE); + menu('admin/system/modules/profile/delete', NULL, 'profile_admin_delete', 0, MENU_HIDE); + } + } +} + +function profile_browse() { + + $value = arg(2) ? arg(2) : 1; + + // Determine the field to group users by: + $field = db_fetch_object(db_query("SELECT DISTINCT(f.fid), f.type, f.title FROM {profile_fields} f INNER JOIN {profile_values} v ON f.fid = v.fid WHERE f.name = '%s' AND v.value = '%s' ORDER BY f.category, f.weight", arg(1), $value)); + + if ($field->fid) { + // Compile a list of fields to show: + $fields = array(); + $result = db_query("SELECT name, title, type FROM {profile_fields} WHERE fid != %d AND overview = 1", $field->fid); + while ($record = db_fetch_object($result)) { + $fields[] = $record; + } + + // Extract the affected users: + $result = pager_query("SELECT u.uid FROM {users} u INNER JOIN {profile_values} v ON u.uid = v.uid WHERE v.fid = $field->fid AND v.value = '". check_query($value) ."' ORDER BY u.changed DESC", 20); + + $output = ''; + while ($account = db_fetch_object($result)) { + $output .= theme('profile_profile', user_load(array('uid' => $account->uid)), $fields); + } + $output .= theme('pager', NULL, 20); + + if ($field->type == "selection") { + $title = arg(2); + } + else { + $title = $field->title; + } + + print theme('page', $output, $title); + } + else { + drupal_not_found(); + } +} + +function profile_load_profile(&$user) { + $result = db_query('SELECT f.name, v.value FROM {profile_fields} f INNER JOIN {profile_values} v ON f.fid = v.fid WHERE uid = %d', $user->uid); + while ($field = db_fetch_object($result)) { + if (empty($user->{$field->name})) { + $user->{$field->name} = $field->value; + } + } +} + +function profile_save_profile($edit, $user) { + db_query('DELETE FROM {profile_values} WHERE uid = %d', $user->uid); + $result = db_query('SELECT fid, name FROM profile_fields'); + while ($field = db_fetch_object($result)) { + if ($edit[$field->name]) { + db_query("INSERT INTO {profile_values} (fid, uid, value) VALUES (%d, %d, '%s')", $field->fid, $user->uid, $edit[$field->name]); + unset($edit[$field->name]); + } + } +} + +function profile_view_profile($user) { + + profile_load_profile(&$user); + + $result = db_query('SELECT * FROM {profile_fields} ORDER BY category, weight'); + while ($field = db_fetch_object($result)) { + if ($value = $user->{$field->name}) { + switch ($field->type) { + case 'textfield': + case 'textarea': + $output .= form_item($field->title, check_output($value)); + break; + case 'selection': + $output .= form_item($field->title, l($value, "profile/$field->name/$value")); + break; + case 'checkbox': + $output .= '

'. l($field->title, "profile/$field->name/") .'

'; + } + } + } + + return $output; } -function profile_settings() { - global $profile_fields; +function profile_edit_profile($edit, $user) { - if (!$profile_fields) { - _profile_init(); + $result = db_query('SELECT * FROM {profile_fields} ORDER BY category, weight'); + + while ($field = db_fetch_object($result)) { + switch ($field->type) { + case 'textfield': + $fields[$field->category] .= form_textfield($field->title, $field->name, $edit[$field->name], 70, 255, $field->explanation); + break; + case 'textarea': + $fields[$field->category] .= form_textarea($field->title, $field->name, $edit[$field->name], 60, 4, $field->explanation); + break; + case 'checkbox': + $fields[$field->category] .= form_checkbox($field->title, $field->name, 1, $edit[$field->name], $field->explanation); + break; + case 'selection': + $options = array('--'); + $lines = split("[\n\r]", $field->options); + foreach ($lines as $line) { + if ($line = trim($line)) { + $options[$line] = $line; + } + } + + $fields[$field->category] .= form_select($field->title, $field->name, $edit[$field->name], $options, $field->explanation); + break; + } } - if (!file_check_directory(file_create_path(variable_get('profile_avatar_path', 'avatars')))) { - $error['profile_avatar_path'] = theme('error', t('Directory does not exist, or is not writable.')); - } - - $profile_public_fields = variable_get("profile_public_fields", array()); - $profile_private_fields = variable_get("profile_private_fields", array()); - $profile_required_fields = variable_get("profile_required_fields", array()); - - $header = array(t("field"), t("enable"), t("public"), t("required")); - $i = 0; - foreach ($profile_fields as $key => $field) { - $row[$i][] = $field[1]; - $row[$i][] = form_checkbox("", "profile_private_fields][", $key, in_array($key, $profile_private_fields)); - $row[$i][] = form_checkbox("", "profile_public_fields][", $key, in_array($key, $profile_public_fields)); - $row[$i][] = form_checkbox("", "profile_required_fields][", $key, in_array($key, $profile_required_fields)); - $i++; - } - - $avatar = form_textfield(t("Avatar image path"), "profile_avatar_path", variable_get("profile_avatar_path", "avatars"), 30, 255, t("Subdirectory in the directory '%dir' where avatars will be stored.", array('%dir' => variable_get('file_directory_path', 'files') . FILE_SEPARATOR)) . $error['profile_avatar_path']); - $avatar .= form_textfield(t("Avatar maximum dimensions"), "profile_avatar_dimensions", variable_get("profile_avatar_dimensions", "85x85"), 10, 10, t("Maximum dimensions for avatars.")); - $avatar .= form_textfield(t("Avatar maximum file size"), "profile_avatar_file_size", variable_get("profile_avatar_file_size", "30"), 10, 10, t("Maximum file size for avatars, in kB.")); - - $output = theme("table", $header, $row); - $output .= form_group(t('Avatars'), $avatar); - - return $output; + return $fields; } function profile_user($type, $edit, &$user) { - global $profile_fields; - if (!$profile_fields) { - _profile_init(); - } - switch ($type) { - case "edit_form": - // when user tries to edit his own data - return _profile_form(object2array($user), "private"); - case "edit_validate": - // validate user data editing - return _profile_validate($edit, "private", $user); - case "view_public": - // when others look at user data - return _profile_user_view($user, "public"); - case "view_private": - // when user looks at his own data - return _profile_user_view($user, "private"); + case 'load': + return profile_load_profile($user); + case 'update': + return profile_save_profile($edit, $user); + case 'view': + return profile_view_profile($user); + case 'edit': + return profile_edit_profile($edit, $user); + case 'validate': + return $edit; } } -function profile_required($title) { - // this pleads "theme, theme" ;) - return $title ." ". theme("mark"); +function profile_validate_form($edit) { + + // Validate the title: + + if (!$edit['title']) { + return t('You must enter a title.'); + } + + // Validate the 'form name': + + if (eregi('[^a-z0-9_-]', $edit['name'])) { + return t('The specified form name contains one or more illegal characters. Spaces or any other special characters expect dash (-) and underscore (_) are not allowed.'); + } + + if (in_array($edit['name'], user_fields())) { + return t('The specified form name is reserved for use by Drupal.'); + } + + // Validate the category: + + if (!$edit['category']) { + return t('You must enter a category.'); + } } -function _profile_form($edit, $mode) { - global $profile_fields, $user; +function profile_admin_add($type) { + $type = _profile_field_types($type); - $reg_fields = _profile_active_fields($mode); - $required_fields = _profile_active_fields("required"); - foreach ($profile_fields as $name => $field) { - if ($field[0] && in_array($name, $reg_fields)) { - $f = "form_". $field[0]; - $t = "profile_". $name; - $output .= $f((in_array($name, $required_fields) ? profile_required($field[1]) : $field[1]), $t, $edit[$t], $field[3], $field[4], $field[5], $field[6]); + if ($_POST['op']) { + $data = $_POST['edit']; + + if ($error = profile_validate_form($data)) { + drupal_set_message($error, 'error'); + } + else { + db_query("INSERT INTO {profile_fields} (title, name, explanation, category, type, weight, overview, options) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d, '%s')", $data['title'], $data['name'], $data['explanation'], $data['category'], $type, $data['weight'], $data['overview'], $data['options']); + + drupal_set_message(t('the field has been created.')); } } - - if (in_array("birthday", $reg_fields)) { - $output .= form_item((in_array("birthday", $required_fields) ? profile_required($profile_fields["birthday"][1]) : $profile_fields["birthday"][1]), _profile_edit_birth(array2object($edit)), $profile_fields["birthday"][2]); + else { + $data = array('name' => 'profile_'); } - if (in_array("avatar", $reg_fields)) { - if ($edit["profile_avatar"] && file_exists($edit["profile_avatar"])) { - $output .= form_item(t("Avatar"), ''); - } - $output .= form_file($profile_fields["avatar"][1], "profile_avatar", 64, $profile_fields["avatar"][2]); - } - - return array(t('Personal information') => $output); + print theme('page', _profile_field_form($type, $data), t('Add new %type', array('%type' => $type))); } -function _profile_validate($edit, $mode, $user) { +function profile_admin_edit($fid) { - global $profile_fields; + if ($_POST['op']) { + $data = $_POST['edit']; - $enabled_fields = _profile_active_fields($mode); + if ($error = profile_validate_form($data)) { + drupal_set_message($error, 'error'); - if (in_array("birthday", $enabled_fields) && ($birth_error = _profile_validate_birth($edit))) { - $error .= $birth_error ."
"; - } + } + else { + db_query("UPDATE {profile_fields} SET title = '%s', name = '%s', explanation = '%s', category = '%s', weight = %d, overview = %d, options = '%s' WHERE fid = %d", $data['title'], $data['name'], $data['explanation'], $data['category'], $data['weight'], $data['overview'], $data['options'], $fid); - if (in_array("avatar", $enabled_fields) && ($avatar_error = _profile_validate_avatar($edit, $user))) { - $error .= $avatar_error ."
"; - } - - foreach (array_keys($profile_fields) as $field) { - // replicate any key which was saved during registration but is not in this form - if (!$edit[$field] && $user->$field) { - $edit[$field] = $user->$field; + drupal_set_message(t('the field has been updated.')); } } + else { + $data = db_fetch_array(db_query('SELECT * FROM {profile_fields} WHERE fid = %d', $fid)); + } - // now check for required fields - foreach (_profile_active_fields("required") as $required) { - if ($required != "0" && in_array($required, $enabled_fields)) { - if (!$edit["profile_". $required]) { - $error .= t("This required field is missing: %a", array("%a" => $profile_fields[$required][1])) ."
"; + print theme('page', _profile_field_form($data['type'], $data), t('Edit %type', array('%type' => $edit['type']))); +} + +function profile_admin_delete($fid) { + db_query('DELETE FROM {profile_fields} WHERE fid = %d', $fid); + drupal_set_message(t('the field has been deleted.')); + print theme('page', '', t('Delete field')); +} + +function _profile_field_form($type, $edit = array()) { + + $output = form_textfield(t('Title'), 'title', $edit['title'], 70, 128, t("The title of the new field. The title will be shown to the user. An example title is 'Favorite color'."), NULL, FORM_REQUIRED); + $output .= form_textfield(t('Form name'), 'name', $edit['name'], 70, 128, t("The name of the field. The form name is not shown to the user but used internally in the HTML code and URLs. +Unless you know what you are doing, it is highly recommended that you prefix the form name with profile_ to avoid name clashes with other fields. Because the form name's usage, spaces or any other special characters except dash (-) and underscore (_) are not allowed. An example for, name is 'profile_favorite_color' or just 'profile_color'.")); + $output .= form_textarea(t('Explanation'), 'explanation', $edit['explanation'], 70, 3, t("An optional explanation to go with the new field. The explanation will be shown to the user.")); + $output .= form_textfield(t('Category'), 'category', $edit['category'], 70, 128, t("The category the new field should be part of. Categories are used to group fields logically. An example category is 'Personal information'.")); + $output .= form_weight(t('Weight'), 'weight', $edit['weight'], 5, t("The weights define the order in which the form fields are shown. Lighter fields \"float up\" towards the top of the category.")); + $output .= form_checkbox(t('Display this field on member listsings'), 'overview', 1, $edit['overview']); + + if ($type == 'selection') { + $output .= form_textarea(t('Selection options'), 'options', $edit['options'], 70, 8, t("A list op all options. Put each option on a separate line. Example options are 'red', 'blue', 'green', etc.")); + } + + $output .= form_submit(t('Save field')); + + return form($output); +} + +function profile_admin_overview() { + + $result = db_query('SELECT * FROM {profile_fields} ORDER BY category, weight'); + while ($field = db_fetch_object($result)) { + $rows[] = array($field->title, $field->name, $field->type, $field->category, l(t('edit'), "admin/system/modules/profile/edit/$field->fid"), l(t('delete'), "admin/system/modules/profile/delete/$field->fid")); + } + + $header = array(t('title'), t('name'), t('type'), t('category'), array('data' => t('operations'), 'colspan' => '2')); + + $output = theme('table', $header, $rows); + $output .= '

'. t('Create new field') .'

'; + $output .= '
    '; + foreach (_profile_field_types() as $key => $value) { + $output .= "
  • ". l(t('Add new %type', array('%type' => $value)), "admin/system/modules/profile/add/$key") ."
  • "; + } + $output .= '
'; + + print theme('page', $output); +} + +function theme_profile_profile($user, $fields = array()) { + + $output = "
\n"; + $output .= theme('user_picture', $user); + $output .= "
". format_name($user) ."
\n"; + + foreach ($fields as $field) { + if ($user->{$field->name}) { + if ($field->type == 'checkbox') { + $output .= "
". $field->title ."
"; + } + else { + $output .= "
". $user->{$field->name} ."
"; } } } - return $error ? $error : $edit; -} + $output .= "
\n"; -function _profile_user_view(&$user, $mode) { - global $profile_fields; - - foreach (_profile_active_fields($mode) as $name) { - $field = $profile_fields[$name]; - $t = "profile_". $name; - - if (!empty($user->$t)) { - switch ($field[0]) { - case "textfield": - case "textarea": - case "checkbox": - $value = ($t == "profile_homepage") ? "$t) ."\">". check_output($user->$t) ."" : check_output($user->$t); - $output .= form_item($field[1], $value); - break; - case "select": - $output .= form_item($field[1], check_output($profile_fields[$name][3][$user->$t])); - break; - case "": - // special - if ($t == "profile_avatar") { - if (file_exists($user->$t)) { - $output .= form_item(t("Avatar"), ''); - } - } - - if ($t == "profile_birthday") { - if (isset($user->profile_birthday) && isset($user->profile_birthmonth) && isset($user->profile_birthyear)) { - // this is very european-centric, can we use format_date? - $time = mktime(0, 0, 0, $user->profile_birthmonth, $user->profile_birthday, $user->profile_birthyear); - $output .= form_item(t("Birthday"), format_date($time, "custom", "F j, Y")); - } - } - } - } - } return $output; } -function profile_file_download($file) { - if (strpos($file, variable_get("profile_avatar_path", "avatars") . FILE_SEPARATOR . 'avatar-') === 0) { - list($width, $height, $type, $attr) = getimagesize(file_create_path($file)); - $types = array( - IMAGETYPE_GIF => 'image/gif', - IMAGETYPE_JPEG => 'image/jpeg', - IMAGETYPE_PNG => 'image/png', - IMAGETYPE_SWF => 'application/x-shockwave-flash', - IMAGETYPE_PSD => 'image/psd', - IMAGETYPE_BMP => 'image/bmp', - IMAGETYPE_TIFF_II => 'image/tiff', - IMAGETYPE_TIFF_MM => 'image/tiff', - IMAGETYPE_JPC => 'application/octet-stream', - IMAGETYPE_JP2 => 'image/jp2', - IMAGETYPE_JPX => 'application/octet-stream', - IMAGETYPE_JB2 => 'application/octet-stream', - IMAGETYPE_SWC => 'application/x-shockwave-flash', - IMAGETYPE_IFF => 'image/iff', - IMAGETYPE_WBMP => 'image/vnd.wap.wbmp', - IMAGETYPE_XBM => 'image/xbm' - ); - return array('Content-type: '. $types[$type]); - } -} - -function _profile_validate_avatar(&$edit, $user) { - // check that uploaded file is an image, with a maximum file size and maximum height/width - - unset($edit["profile_avatar"]); - - if (!$file = file_check_upload('profile_avatar')) { - $edit["profile_avatar"] = $user->profile_avatar; - return; - } - - $extension = strtolower(strrchr($file->name, ".")); - $size = getimagesize($file->path); - list($maxwidth, $maxheight) = explode("x", variable_get("profile_avatar_dimensions", "85x85")); - if ((!in_array($size[2], array(1, 2, 3))) || (!in_array($extension, array(".gif", ".jpg", ".png", ".jpeg")))) { - $error = t("The uploaded file was not an image."); - } - else if ($file->size > (variable_get("profile_avatar_file_size", "30") * 1000)) { - $error = t("The uploaded image is too large; the maximum file size is %a kB.", array("%a" => variable_get("profile_avatar_file_size", "30"))); - } - else if ($size[0] > $maxwidth || $size[1] > $maxheight) { - $error = t("The uploaded image is too large; the maximum dimensions are %a pixels.", array("%a" => variable_get("profile_avatar_dimensions", "85x85"))); - } - else if ($file = file_save_upload('profile_avatar', variable_get("profile_avatar_path", "avatars") . FILE_SEPARATOR .'avatar-'. $user->uid . $extension, 1)) { - $edit["profile_avatar"] = $file->path; - } - else { - $error = t("Failed to upload the avatar image; the '%directory' directory doesn't exist.", array("%directory" => variable_get("profile_avatar_path", "avatars"))); - } - - return $error ? "$error
" : ""; -} - -function _profile_active_fields($mode) { - return variable_get("profile_". $mode ."_fields", array()); -} - -function _profile_edit_birth($edit = "") { - global $profile_months, $profile_days; - $output = _profile_select("profile_birthday", $edit->profile_birthday, $profile_days); - $output .= " "; - $output .= _profile_select("profile_birthmonth", $edit->profile_birthmonth, $profile_months); - $output .= " "; - $output .= "profile_birthyear\" />"; - return $output; -} - -function _profile_validate_birth(&$edit) { - if (!$edit["profile_birthday"] && !$edit["profile_birthmonth"] && !$edit["profile_birthyear"]) { - // change this if you want required birth - return; - } - - if ($edit["profile_birthyear"] > 1900 && checkdate($edit["profile_birthmonth"], $edit["profile_birthday"], $edit["profile_birthyear"])) { - return; - } - else { - return t("The specified birthday is not valid.") ."
"; - } -} - -function _profile_select($name, $value, $options, $extra = 0, $multiple = 0) { - if (count($options) > 0) { - foreach ($options as $key=>$choice) { - $select .= ""; - } - return ""; - } +function _profile_field_types($type = NULL) { + $types = array('textfield', 'textarea', 'checkbox', 'selection'); + return isset($type) ? $types[$type] : $types; } ?> diff --git a/modules/profile/profile.module b/modules/profile/profile.module index a16c47c204f..d1e5e5f0c9a 100644 --- a/modules/profile/profile.module +++ b/modules/profile/profile.module @@ -1,306 +1,300 @@ array("textfield", t("Name"), "", 64, 64, ""), - "address" => array("textfield", t("Address"), "", 64, 64, ""), - "city" => array("textfield", t("City"), "", 64, 64, ""), - "state" => array("textfield", t("State, province or region"), "", 64, 64, ""), - "zip" => array("textfield", t("Zip or postal code"), "", 7, 10, ""), - "country" => array("textfield", t("Country"), "", 64, 64, ""), - "birthday" => array("", t("Birthday"), ""), - "gender" => array("select", t("Gender"), "", array(0 => "-", "m" => t("male"), "f" => t("female")), "", 0, 0), - "job" => array("textfield", t("Job title"), "", 64, 64, ""), - "icq" => array("textfield", t("ICQ messenger ID"), "", 12, 12, ""), - "msn" => array("textfield", t("MSN messenger ID"), "", 64, 64, ""), - "yahoo" => array("textfield", t("Yahoo messenger ID"), "", 64, 64, ""), - "aim" => array("textfield", t("AIM messenger ID"), "", 64, 64, ""), - "homepage" => array("textfield", t("URL of homepage"), "", 64, 64, t("Make sure you enter a fully qualified URL: remember to include \"http://\".")), - "biography" => array("textarea", t("Biography"), "", 64, 4, ""), - "interests" => array("textarea", t("Interests"), "", 64, 4, ""), - "publickey" => array("textarea", t("Public key"), "", 64, 4, ""), - "avatar" => array("", t("Avatar or picture"), t("Your virtual face or picture. Maximum dimensions are %dimensions and the maximum size is %size kB.", array("%dimensions" => variable_get("profile_avatar_dimensions", "85x85"), "%size" => variable_get("profile_avatar_file_size", "30")))) - ); - - $GLOBALS["profile_days"] = array_merge(array(0 => t("day")), drupal_map_assoc(range(1, 31))); - $GLOBALS["profile_months"] = array(0 => t("month"), 1 => t("January"), 2 => t("February"), 3 => t("March"), 4 => t("April"), 5 => t("May"), 6 => t("June"), 7 => t("July"), 8 => t("August"), 9 => t("September"), 10 => t("October"), 11 => t("November"), 12 => t("December")); -} +// TODO: add a 'date' field so we can migrate the birthday information. function profile_help($section) { - $output = ""; - switch ($section) { case 'admin/system/modules#description': $output = t("Support for configurable user profiles."); break; - case 'admin/system/modules/profile': - $output = t("When a user creates an account you can ask for some extra information, as well as letting the user have a small picture, called an avatar.
  • In order for a user to enter information, you must check enable.
  • In order for other people to see the entered information, you must make it public.
  • If an item is public, but not enabled, the user can never give it a value and it will never be seen. Public does not imply enable.
", array("%edit" => url("user/edit"))); - break; } return $output; + + +} + +function profile_link($type) { + if ($type == 'system') { + menu('profile', t('browse'), 'profile_browse', 0, MENU_HIDE); + + if (user_access('administer users')) { + menu('admin/system/modules/profile', t('profile'), 'profile_admin_overview'); + menu('admin/system/modules/profile/add', NULL, 'profile_admin_add', 0, MENU_HIDE); + menu('admin/system/modules/profile/edit', NULL, 'profile_admin_edit', 0, MENU_HIDE); + menu('admin/system/modules/profile/delete', NULL, 'profile_admin_delete', 0, MENU_HIDE); + } + } +} + +function profile_browse() { + + $value = arg(2) ? arg(2) : 1; + + // Determine the field to group users by: + $field = db_fetch_object(db_query("SELECT DISTINCT(f.fid), f.type, f.title FROM {profile_fields} f INNER JOIN {profile_values} v ON f.fid = v.fid WHERE f.name = '%s' AND v.value = '%s' ORDER BY f.category, f.weight", arg(1), $value)); + + if ($field->fid) { + // Compile a list of fields to show: + $fields = array(); + $result = db_query("SELECT name, title, type FROM {profile_fields} WHERE fid != %d AND overview = 1", $field->fid); + while ($record = db_fetch_object($result)) { + $fields[] = $record; + } + + // Extract the affected users: + $result = pager_query("SELECT u.uid FROM {users} u INNER JOIN {profile_values} v ON u.uid = v.uid WHERE v.fid = $field->fid AND v.value = '". check_query($value) ."' ORDER BY u.changed DESC", 20); + + $output = ''; + while ($account = db_fetch_object($result)) { + $output .= theme('profile_profile', user_load(array('uid' => $account->uid)), $fields); + } + $output .= theme('pager', NULL, 20); + + if ($field->type == "selection") { + $title = arg(2); + } + else { + $title = $field->title; + } + + print theme('page', $output, $title); + } + else { + drupal_not_found(); + } +} + +function profile_load_profile(&$user) { + $result = db_query('SELECT f.name, v.value FROM {profile_fields} f INNER JOIN {profile_values} v ON f.fid = v.fid WHERE uid = %d', $user->uid); + while ($field = db_fetch_object($result)) { + if (empty($user->{$field->name})) { + $user->{$field->name} = $field->value; + } + } +} + +function profile_save_profile($edit, $user) { + db_query('DELETE FROM {profile_values} WHERE uid = %d', $user->uid); + $result = db_query('SELECT fid, name FROM profile_fields'); + while ($field = db_fetch_object($result)) { + if ($edit[$field->name]) { + db_query("INSERT INTO {profile_values} (fid, uid, value) VALUES (%d, %d, '%s')", $field->fid, $user->uid, $edit[$field->name]); + unset($edit[$field->name]); + } + } +} + +function profile_view_profile($user) { + + profile_load_profile(&$user); + + $result = db_query('SELECT * FROM {profile_fields} ORDER BY category, weight'); + while ($field = db_fetch_object($result)) { + if ($value = $user->{$field->name}) { + switch ($field->type) { + case 'textfield': + case 'textarea': + $output .= form_item($field->title, check_output($value)); + break; + case 'selection': + $output .= form_item($field->title, l($value, "profile/$field->name/$value")); + break; + case 'checkbox': + $output .= '

'. l($field->title, "profile/$field->name/") .'

'; + } + } + } + + return $output; } -function profile_settings() { - global $profile_fields; +function profile_edit_profile($edit, $user) { - if (!$profile_fields) { - _profile_init(); + $result = db_query('SELECT * FROM {profile_fields} ORDER BY category, weight'); + + while ($field = db_fetch_object($result)) { + switch ($field->type) { + case 'textfield': + $fields[$field->category] .= form_textfield($field->title, $field->name, $edit[$field->name], 70, 255, $field->explanation); + break; + case 'textarea': + $fields[$field->category] .= form_textarea($field->title, $field->name, $edit[$field->name], 60, 4, $field->explanation); + break; + case 'checkbox': + $fields[$field->category] .= form_checkbox($field->title, $field->name, 1, $edit[$field->name], $field->explanation); + break; + case 'selection': + $options = array('--'); + $lines = split("[\n\r]", $field->options); + foreach ($lines as $line) { + if ($line = trim($line)) { + $options[$line] = $line; + } + } + + $fields[$field->category] .= form_select($field->title, $field->name, $edit[$field->name], $options, $field->explanation); + break; + } } - if (!file_check_directory(file_create_path(variable_get('profile_avatar_path', 'avatars')))) { - $error['profile_avatar_path'] = theme('error', t('Directory does not exist, or is not writable.')); - } - - $profile_public_fields = variable_get("profile_public_fields", array()); - $profile_private_fields = variable_get("profile_private_fields", array()); - $profile_required_fields = variable_get("profile_required_fields", array()); - - $header = array(t("field"), t("enable"), t("public"), t("required")); - $i = 0; - foreach ($profile_fields as $key => $field) { - $row[$i][] = $field[1]; - $row[$i][] = form_checkbox("", "profile_private_fields][", $key, in_array($key, $profile_private_fields)); - $row[$i][] = form_checkbox("", "profile_public_fields][", $key, in_array($key, $profile_public_fields)); - $row[$i][] = form_checkbox("", "profile_required_fields][", $key, in_array($key, $profile_required_fields)); - $i++; - } - - $avatar = form_textfield(t("Avatar image path"), "profile_avatar_path", variable_get("profile_avatar_path", "avatars"), 30, 255, t("Subdirectory in the directory '%dir' where avatars will be stored.", array('%dir' => variable_get('file_directory_path', 'files') . FILE_SEPARATOR)) . $error['profile_avatar_path']); - $avatar .= form_textfield(t("Avatar maximum dimensions"), "profile_avatar_dimensions", variable_get("profile_avatar_dimensions", "85x85"), 10, 10, t("Maximum dimensions for avatars.")); - $avatar .= form_textfield(t("Avatar maximum file size"), "profile_avatar_file_size", variable_get("profile_avatar_file_size", "30"), 10, 10, t("Maximum file size for avatars, in kB.")); - - $output = theme("table", $header, $row); - $output .= form_group(t('Avatars'), $avatar); - - return $output; + return $fields; } function profile_user($type, $edit, &$user) { - global $profile_fields; - if (!$profile_fields) { - _profile_init(); - } - switch ($type) { - case "edit_form": - // when user tries to edit his own data - return _profile_form(object2array($user), "private"); - case "edit_validate": - // validate user data editing - return _profile_validate($edit, "private", $user); - case "view_public": - // when others look at user data - return _profile_user_view($user, "public"); - case "view_private": - // when user looks at his own data - return _profile_user_view($user, "private"); + case 'load': + return profile_load_profile($user); + case 'update': + return profile_save_profile($edit, $user); + case 'view': + return profile_view_profile($user); + case 'edit': + return profile_edit_profile($edit, $user); + case 'validate': + return $edit; } } -function profile_required($title) { - // this pleads "theme, theme" ;) - return $title ." ". theme("mark"); +function profile_validate_form($edit) { + + // Validate the title: + + if (!$edit['title']) { + return t('You must enter a title.'); + } + + // Validate the 'form name': + + if (eregi('[^a-z0-9_-]', $edit['name'])) { + return t('The specified form name contains one or more illegal characters. Spaces or any other special characters expect dash (-) and underscore (_) are not allowed.'); + } + + if (in_array($edit['name'], user_fields())) { + return t('The specified form name is reserved for use by Drupal.'); + } + + // Validate the category: + + if (!$edit['category']) { + return t('You must enter a category.'); + } } -function _profile_form($edit, $mode) { - global $profile_fields, $user; +function profile_admin_add($type) { + $type = _profile_field_types($type); - $reg_fields = _profile_active_fields($mode); - $required_fields = _profile_active_fields("required"); - foreach ($profile_fields as $name => $field) { - if ($field[0] && in_array($name, $reg_fields)) { - $f = "form_". $field[0]; - $t = "profile_". $name; - $output .= $f((in_array($name, $required_fields) ? profile_required($field[1]) : $field[1]), $t, $edit[$t], $field[3], $field[4], $field[5], $field[6]); + if ($_POST['op']) { + $data = $_POST['edit']; + + if ($error = profile_validate_form($data)) { + drupal_set_message($error, 'error'); + } + else { + db_query("INSERT INTO {profile_fields} (title, name, explanation, category, type, weight, overview, options) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d, '%s')", $data['title'], $data['name'], $data['explanation'], $data['category'], $type, $data['weight'], $data['overview'], $data['options']); + + drupal_set_message(t('the field has been created.')); } } - - if (in_array("birthday", $reg_fields)) { - $output .= form_item((in_array("birthday", $required_fields) ? profile_required($profile_fields["birthday"][1]) : $profile_fields["birthday"][1]), _profile_edit_birth(array2object($edit)), $profile_fields["birthday"][2]); + else { + $data = array('name' => 'profile_'); } - if (in_array("avatar", $reg_fields)) { - if ($edit["profile_avatar"] && file_exists($edit["profile_avatar"])) { - $output .= form_item(t("Avatar"), ''); - } - $output .= form_file($profile_fields["avatar"][1], "profile_avatar", 64, $profile_fields["avatar"][2]); - } - - return array(t('Personal information') => $output); + print theme('page', _profile_field_form($type, $data), t('Add new %type', array('%type' => $type))); } -function _profile_validate($edit, $mode, $user) { +function profile_admin_edit($fid) { - global $profile_fields; + if ($_POST['op']) { + $data = $_POST['edit']; - $enabled_fields = _profile_active_fields($mode); + if ($error = profile_validate_form($data)) { + drupal_set_message($error, 'error'); - if (in_array("birthday", $enabled_fields) && ($birth_error = _profile_validate_birth($edit))) { - $error .= $birth_error ."
"; - } + } + else { + db_query("UPDATE {profile_fields} SET title = '%s', name = '%s', explanation = '%s', category = '%s', weight = %d, overview = %d, options = '%s' WHERE fid = %d", $data['title'], $data['name'], $data['explanation'], $data['category'], $data['weight'], $data['overview'], $data['options'], $fid); - if (in_array("avatar", $enabled_fields) && ($avatar_error = _profile_validate_avatar($edit, $user))) { - $error .= $avatar_error ."
"; - } - - foreach (array_keys($profile_fields) as $field) { - // replicate any key which was saved during registration but is not in this form - if (!$edit[$field] && $user->$field) { - $edit[$field] = $user->$field; + drupal_set_message(t('the field has been updated.')); } } + else { + $data = db_fetch_array(db_query('SELECT * FROM {profile_fields} WHERE fid = %d', $fid)); + } - // now check for required fields - foreach (_profile_active_fields("required") as $required) { - if ($required != "0" && in_array($required, $enabled_fields)) { - if (!$edit["profile_". $required]) { - $error .= t("This required field is missing: %a", array("%a" => $profile_fields[$required][1])) ."
"; + print theme('page', _profile_field_form($data['type'], $data), t('Edit %type', array('%type' => $edit['type']))); +} + +function profile_admin_delete($fid) { + db_query('DELETE FROM {profile_fields} WHERE fid = %d', $fid); + drupal_set_message(t('the field has been deleted.')); + print theme('page', '', t('Delete field')); +} + +function _profile_field_form($type, $edit = array()) { + + $output = form_textfield(t('Title'), 'title', $edit['title'], 70, 128, t("The title of the new field. The title will be shown to the user. An example title is 'Favorite color'."), NULL, FORM_REQUIRED); + $output .= form_textfield(t('Form name'), 'name', $edit['name'], 70, 128, t("The name of the field. The form name is not shown to the user but used internally in the HTML code and URLs. +Unless you know what you are doing, it is highly recommended that you prefix the form name with profile_ to avoid name clashes with other fields. Because the form name's usage, spaces or any other special characters except dash (-) and underscore (_) are not allowed. An example for, name is 'profile_favorite_color' or just 'profile_color'.")); + $output .= form_textarea(t('Explanation'), 'explanation', $edit['explanation'], 70, 3, t("An optional explanation to go with the new field. The explanation will be shown to the user.")); + $output .= form_textfield(t('Category'), 'category', $edit['category'], 70, 128, t("The category the new field should be part of. Categories are used to group fields logically. An example category is 'Personal information'.")); + $output .= form_weight(t('Weight'), 'weight', $edit['weight'], 5, t("The weights define the order in which the form fields are shown. Lighter fields \"float up\" towards the top of the category.")); + $output .= form_checkbox(t('Display this field on member listsings'), 'overview', 1, $edit['overview']); + + if ($type == 'selection') { + $output .= form_textarea(t('Selection options'), 'options', $edit['options'], 70, 8, t("A list op all options. Put each option on a separate line. Example options are 'red', 'blue', 'green', etc.")); + } + + $output .= form_submit(t('Save field')); + + return form($output); +} + +function profile_admin_overview() { + + $result = db_query('SELECT * FROM {profile_fields} ORDER BY category, weight'); + while ($field = db_fetch_object($result)) { + $rows[] = array($field->title, $field->name, $field->type, $field->category, l(t('edit'), "admin/system/modules/profile/edit/$field->fid"), l(t('delete'), "admin/system/modules/profile/delete/$field->fid")); + } + + $header = array(t('title'), t('name'), t('type'), t('category'), array('data' => t('operations'), 'colspan' => '2')); + + $output = theme('table', $header, $rows); + $output .= '

'. t('Create new field') .'

'; + $output .= '
    '; + foreach (_profile_field_types() as $key => $value) { + $output .= "
  • ". l(t('Add new %type', array('%type' => $value)), "admin/system/modules/profile/add/$key") ."
  • "; + } + $output .= '
'; + + print theme('page', $output); +} + +function theme_profile_profile($user, $fields = array()) { + + $output = "
\n"; + $output .= theme('user_picture', $user); + $output .= "
". format_name($user) ."
\n"; + + foreach ($fields as $field) { + if ($user->{$field->name}) { + if ($field->type == 'checkbox') { + $output .= "
". $field->title ."
"; + } + else { + $output .= "
". $user->{$field->name} ."
"; } } } - return $error ? $error : $edit; -} + $output .= "
\n"; -function _profile_user_view(&$user, $mode) { - global $profile_fields; - - foreach (_profile_active_fields($mode) as $name) { - $field = $profile_fields[$name]; - $t = "profile_". $name; - - if (!empty($user->$t)) { - switch ($field[0]) { - case "textfield": - case "textarea": - case "checkbox": - $value = ($t == "profile_homepage") ? "$t) ."\">". check_output($user->$t) ."" : check_output($user->$t); - $output .= form_item($field[1], $value); - break; - case "select": - $output .= form_item($field[1], check_output($profile_fields[$name][3][$user->$t])); - break; - case "": - // special - if ($t == "profile_avatar") { - if (file_exists($user->$t)) { - $output .= form_item(t("Avatar"), ''); - } - } - - if ($t == "profile_birthday") { - if (isset($user->profile_birthday) && isset($user->profile_birthmonth) && isset($user->profile_birthyear)) { - // this is very european-centric, can we use format_date? - $time = mktime(0, 0, 0, $user->profile_birthmonth, $user->profile_birthday, $user->profile_birthyear); - $output .= form_item(t("Birthday"), format_date($time, "custom", "F j, Y")); - } - } - } - } - } return $output; } -function profile_file_download($file) { - if (strpos($file, variable_get("profile_avatar_path", "avatars") . FILE_SEPARATOR . 'avatar-') === 0) { - list($width, $height, $type, $attr) = getimagesize(file_create_path($file)); - $types = array( - IMAGETYPE_GIF => 'image/gif', - IMAGETYPE_JPEG => 'image/jpeg', - IMAGETYPE_PNG => 'image/png', - IMAGETYPE_SWF => 'application/x-shockwave-flash', - IMAGETYPE_PSD => 'image/psd', - IMAGETYPE_BMP => 'image/bmp', - IMAGETYPE_TIFF_II => 'image/tiff', - IMAGETYPE_TIFF_MM => 'image/tiff', - IMAGETYPE_JPC => 'application/octet-stream', - IMAGETYPE_JP2 => 'image/jp2', - IMAGETYPE_JPX => 'application/octet-stream', - IMAGETYPE_JB2 => 'application/octet-stream', - IMAGETYPE_SWC => 'application/x-shockwave-flash', - IMAGETYPE_IFF => 'image/iff', - IMAGETYPE_WBMP => 'image/vnd.wap.wbmp', - IMAGETYPE_XBM => 'image/xbm' - ); - return array('Content-type: '. $types[$type]); - } -} - -function _profile_validate_avatar(&$edit, $user) { - // check that uploaded file is an image, with a maximum file size and maximum height/width - - unset($edit["profile_avatar"]); - - if (!$file = file_check_upload('profile_avatar')) { - $edit["profile_avatar"] = $user->profile_avatar; - return; - } - - $extension = strtolower(strrchr($file->name, ".")); - $size = getimagesize($file->path); - list($maxwidth, $maxheight) = explode("x", variable_get("profile_avatar_dimensions", "85x85")); - if ((!in_array($size[2], array(1, 2, 3))) || (!in_array($extension, array(".gif", ".jpg", ".png", ".jpeg")))) { - $error = t("The uploaded file was not an image."); - } - else if ($file->size > (variable_get("profile_avatar_file_size", "30") * 1000)) { - $error = t("The uploaded image is too large; the maximum file size is %a kB.", array("%a" => variable_get("profile_avatar_file_size", "30"))); - } - else if ($size[0] > $maxwidth || $size[1] > $maxheight) { - $error = t("The uploaded image is too large; the maximum dimensions are %a pixels.", array("%a" => variable_get("profile_avatar_dimensions", "85x85"))); - } - else if ($file = file_save_upload('profile_avatar', variable_get("profile_avatar_path", "avatars") . FILE_SEPARATOR .'avatar-'. $user->uid . $extension, 1)) { - $edit["profile_avatar"] = $file->path; - } - else { - $error = t("Failed to upload the avatar image; the '%directory' directory doesn't exist.", array("%directory" => variable_get("profile_avatar_path", "avatars"))); - } - - return $error ? "$error
" : ""; -} - -function _profile_active_fields($mode) { - return variable_get("profile_". $mode ."_fields", array()); -} - -function _profile_edit_birth($edit = "") { - global $profile_months, $profile_days; - $output = _profile_select("profile_birthday", $edit->profile_birthday, $profile_days); - $output .= " "; - $output .= _profile_select("profile_birthmonth", $edit->profile_birthmonth, $profile_months); - $output .= " "; - $output .= "profile_birthyear\" />"; - return $output; -} - -function _profile_validate_birth(&$edit) { - if (!$edit["profile_birthday"] && !$edit["profile_birthmonth"] && !$edit["profile_birthyear"]) { - // change this if you want required birth - return; - } - - if ($edit["profile_birthyear"] > 1900 && checkdate($edit["profile_birthmonth"], $edit["profile_birthday"], $edit["profile_birthyear"])) { - return; - } - else { - return t("The specified birthday is not valid.") ."
"; - } -} - -function _profile_select($name, $value, $options, $extra = 0, $multiple = 0) { - if (count($options) > 0) { - foreach ($options as $key=>$choice) { - $select .= ""; - } - return ""; - } +function _profile_field_types($type = NULL) { + $types = array('textfield', 'textarea', 'checkbox', 'selection'); + return isset($type) ? $types[$type] : $types; } ?> diff --git a/modules/system.module b/modules/system.module index 046920158cf..7169250d5d6 100644 --- a/modules/system.module +++ b/modules/system.module @@ -77,7 +77,7 @@ function system_link($type) { } function system_user($type, $edit, &$user) { - if ($type == "edit_form") { + if ($type == 'edit') { $options = "\n"; if (count($themes = list_themes()) > 1) { foreach ($themes as $key => $value) { diff --git a/modules/system/system.module b/modules/system/system.module index 046920158cf..7169250d5d6 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -77,7 +77,7 @@ function system_link($type) { } function system_user($type, $edit, &$user) { - if ($type == "edit_form") { + if ($type == 'edit') { $options = "\n"; if (count($themes = list_themes()) > 1) { foreach ($themes as $key => $value) { diff --git a/modules/tracker.module b/modules/tracker.module index 6bbc80f4347..8e5d8a11c6a 100644 --- a/modules/tracker.module +++ b/modules/tracker.module @@ -79,12 +79,8 @@ function tracker_posts($id = 0) { } function tracker_user($type, &$edit, &$user) { - switch ($type) { - case "view_private": - case "view_public": - if (user_access("access content")) { - return form_item(t("Recent posts"), l(t("recent posts"), "tracker/$user->uid")); - } + if ($type == 'view' && user_access("access content")) { + return form_item(t("Recent posts"), l(t("recent posts"), "tracker/$user->uid")); } } diff --git a/modules/tracker/tracker.module b/modules/tracker/tracker.module index 6bbc80f4347..8e5d8a11c6a 100644 --- a/modules/tracker/tracker.module +++ b/modules/tracker/tracker.module @@ -79,12 +79,8 @@ function tracker_posts($id = 0) { } function tracker_user($type, &$edit, &$user) { - switch ($type) { - case "view_private": - case "view_public": - if (user_access("access content")) { - return form_item(t("Recent posts"), l(t("recent posts"), "tracker/$user->uid")); - } + if ($type == 'view' && user_access("access content")) { + return form_item(t("Recent posts"), l(t("recent posts"), "tracker/$user->uid")); } } diff --git a/modules/user.module b/modules/user.module index 68d25921a2d..1dbc33dafe4 100644 --- a/modules/user.module +++ b/modules/user.module @@ -78,12 +78,13 @@ function user_save($account, $array = array()) { $query .= "data = '%s', "; $v[] = serialize($data); - db_query("UPDATE {users} SET $query timestamp = %d WHERE uid = %d", array_merge($v, array(time(), $account->uid))); + db_query("UPDATE {users} SET $query changed = %d WHERE uid = %d", array_merge($v, array(time(), $account->uid))); $user = user_load(array('uid' => $account->uid)); } else { - $array['timestamp'] = time(); + $array['created'] = time(); + $array['changed'] = time(); $array['uid'] = db_next_id("{users}_uid"); foreach ($array as $key => $value) { @@ -112,11 +113,11 @@ function user_save($account, $array = array()) { $user = user_load(array('name' => $array['name'])); - module_invoke_all('user', "insert", $array, $user); + module_invoke_all('user', 'insert', $array, $user); } foreach ($array as $key => $value) { - if (substr($key, 0, 4) == "auth") { + if (substr($key, 0, 4) == 'auth') { $authmaps[$key] = $value; } } @@ -136,7 +137,7 @@ function user_validate_name($name) { if (!$name) return t("You must enter a username."); if (substr($name, 0, 1) == ' ') return t("The username cannot begin with a space."); if (substr($name, -1) == ' ') return t("The username cannot end with a space."); - if (ereg(" ", $name)) return t("The username cannot contain multiple spaces in a row."); + if (ereg(' ', $name)) return t("The username cannot contain multiple spaces in a row."); if (ereg('[^ [:alnum:]@_.-]', $name)) return t("The username contains an illegal character."); if (ereg('@', $name) && !eregi('@([0-9a-z](-?[0-9a-z])*.)+[a-z]{2}([zmuvtg]|fo|me)?$', $name)) return t("The username is not a valid authentication ID."); if (strlen($name) > 56) return t("The username '%name' is too long: it must be less than 56 characters.", array("%name" => $name)); @@ -149,6 +150,35 @@ function user_validate_mail($mail) { } } +function user_validate_picture($file, &$edit, $user) { + + // initialize the picture: + $edit['picture'] = $user->picture; + + // check that uploaded file is an image, with a maximum file size and maximum height/width + $extension = strtolower(strrchr($file->name, ".")); + $size = getimagesize($file->path); + list($maxwidth, $maxheight) = explode("x", variable_get('user_picture_dimensions', "85x85")); + + if ((!in_array($size[2], array(1, 2, 3))) || (!in_array($extension, array(".gif", ".jpg", ".png", ".jpeg")))) { + $error = t("The uploaded file was not an image."); + } + else if ($file->size > (variable_get('user_picture_file_size', "30") * 1000)) { + $error = t("The uploaded image is too large; the maximum file size is %a kB.", array("%a" => variable_get('user_picture_file_size', "30"))); + } + else if ($size[0] > $maxwidth || $size[1] > $maxheight) { + $error = t("The uploaded image is too large; the maximum dimensions are %a pixels.", array("%a" => variable_get('user_picture_dimensions', "85x85"))); + } + else if ($file = file_save_upload('picture', variable_get('user_picture_path', "pictures") . FILE_SEPARATOR .'picture-'. $user->uid . $extension, 1)) { + $edit['picture'] = $file->path; + } + else { + $error = t("Failed to upload the picture image; the '%directory' directory doesn't exist.", array("%directory" => variable_get('user_picture_path', "pictures"))); + } + + return $error; +} + function user_validate_authmap($account, $authname, $module) { $result = db_query("SELECT COUNT(*) from {authmap} WHERE uid != %d AND authname = '%s'", $account->uid, $authname); if (db_result($result) > 0) { @@ -281,7 +311,7 @@ function user_fields() { } else { // Make sure we return the default fields at least - $fields = array('uid', 'name', 'pass', "mail", "mode", "sort", "threshold", "theme", "signature", "timestamp", "status", "timezone", "language", "init", "data", "rid"); + $fields = array('uid', 'name', 'pass', "mail", "picture", "mode", "sort", "threshold", "theme", "signature", "created", "changed", "status", "timezone", "language", "init", "data", "rid"); } } @@ -428,6 +458,42 @@ function user_block($op = "list", $delta = 0) { } } +function theme_user_picture($account) { + if (variable_get('user_pictures', 0)) { + if ($account->picture && file_exists($account->picture)) { + $picture = file_create_url($account->picture); + } + else if (variable_get('user_picture_default', '')) { + $picture = variable_get('user_picture_default', ''); + } + + if ($picture) { + $picture = "\"" $account->name ? $account->name : t(variable_get("anonymous", "Anonymous")))) . "\" />"; + if ($account->uid) { + $picture = l($picture, "user/view/$account->uid", array("title" => t("View user profile."))); + } + + return "
$picture
"; + } + } +} + +function theme_user_profile($account) { + $output = "
\n"; + $output .= theme('user_picture', $account); + $output .= form_item(t('Name'), $account->name); + $output .= implode("\n", module_invoke_all('user', 'view', '', $account)); + $output .= form_item(t('Member for'), format_interval(time() - $account->created)); + + if (user_access("administer users")) { + $output .= form_item(t("Administration"), l(t("edit account"), "admin/user/edit/$account->uid")); + } + + $output .= "
\n"; + + return $output; +} + function theme_user_list($items, $title = NULL) { return theme("item_list", $items, $title); } @@ -595,7 +661,7 @@ function user_login($edit = array(), $msg = "") { watchdog('user', "session opened for '$user->name'"); // update the user table timestamp noting user has logged in - db_query("UPDATE {users} SET timestamp = '%d' WHERE uid = '%s'", time(), $user->uid); + db_query("UPDATE {users} SET changed = '%d' WHERE uid = '%s'", time(), $user->uid); user_module_invoke("login", $edit, $user); @@ -685,7 +751,7 @@ function user_logout() { */ session_destroy(); - module_invoke_all('user', "logout", NULL, $user); + module_invoke_all('user', 'logout', NULL, $user); unset($user); } @@ -884,7 +950,15 @@ function user_edit($edit = array()) { else if ($edit['mail'] && db_num_rows(db_query("SELECT uid FROM {users} WHERE uid != '$user->uid' AND LOWER(mail) = LOWER('%s')", $edit['mail'])) > 0) { $error = t("The e-mail address '%s' is already taken.", array("%s" => $edit['mail'])); } - else if ($user->uid) { + else { + /* + ** If required, validate the picture. + */ + + if ($file = file_check_upload('picture')) { + $error = user_validate_picture($file, $edit, $user); + } + /* ** If required, check that proposed passwords match. If so, ** add new password to $edit. @@ -922,7 +996,7 @@ function user_edit($edit = array()) { foreach (module_list() as $module) { if (module_hook($module, 'user')) { - $result = module_invoke($module, 'user', "edit_validate", $edit, $user); + $result = module_invoke($module, 'user', 'validate', $edit, $user); } if (is_array($result)) { $data = array_merge($data, $result); @@ -940,7 +1014,7 @@ function user_edit($edit = array()) { $user = user_save($user, array_merge($edit, $data)); - drupal_set_message(t("your user information changes have been saved.")); + drupal_set_message(t('your user information changes have been saved.')); } } } @@ -953,15 +1027,25 @@ function user_edit($edit = array()) { $edit = object2array($user); } - $output = form_textfield(t("Username"), 'name', $edit['name'], 30, 55, t("Your full name or your preferred username: only letters, numbers and spaces are allowed.")); - $output .= form_textfield(t("E-mail address"), "mail", $edit['mail'], 30, 55, t("Insert a valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.")); - $output .= form_item(t("Password"), " ", t("Enter your new password twice if you want to change your current password or leave it blank if you are happy with your current password.")); - $output = form_group(t('Account information'), $output); + $group = form_textfield(t("Username"), 'name', $edit['name'], 30, 55, t("Your full name or your preferred username: only letters, numbers and spaces are allowed.")); + $group .= form_textfield(t("E-mail address"), "mail", $edit['mail'], 30, 55, t("Insert a valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.")); + $group .= form_item(t("Password"), " ", t("Enter your new password twice if you want to change your current password or leave it blank if you are happy with your current password.")); + $output = form_group(t('Account information'), $group); + + if (variable_get('user_pictures', 0)) { + $group = ''; + if (file_exists($user->picture)) { + $group .= ''; + } + $group .= form_file(t('Upload picture or picture'), 'picture', 48, t("Your virtual face or picture. Maximum dimensions are %dimensions and the maximum size is %size kB.", array("%dimensions" => variable_get('user_picture_dimensions', "85x85"), "%size" => variable_get('user_picture_file_size', "30"))) ." ". variable_get('user_picture_guidelines', '')); + $output .= form_group(t('Picture'), $group); + } + $output .= _user_profile($edit, $user); $output .= form_submit(t("Save user information")); $output = form($output, "post", 0, array("enctype" => "multipart/form-data")); - // the "enctype" attribute is required to upload files such as avatars + // the "enctype" attribute is required to upload files such as pictures } else { $output = user_login(); @@ -973,7 +1057,7 @@ function user_edit($edit = array()) { function _user_profile($edit, $account) { foreach (module_list() as $module) { - if ($data = module_invoke($module, 'user', 'edit_form', $edit, $account)) { + if ($data = module_invoke($module, 'user', 'edit', $edit, $account)) { foreach ($data as $title => $form) { $groups[$title] .= $form; } @@ -991,37 +1075,27 @@ function _user_profile($edit, $account) { function user_view($uid = 0) { global $user; - if (!$uid) { - $uid = $user->uid; - } - - if ($user->uid && $user->uid == $uid) { - $output = form_item(t("Name"), "$user->name ($user->init)"); - $output .= form_item(t("E-mail address"), $user->mail, t("Please note that only you can see your own e-mail address - it is not publicly visible.")); - - $output .= implode("\n", module_invoke_all('user', "view_private", "", $user)); - - print theme('page', $output, $user->name); - } - else if ($uid && $account = user_load(array('uid' => $uid, "status" => 1))) { - $output = form_item(t("Name"), $account->name); - - $output .= implode("\n", module_invoke_all('user', "view_public", "", $account)); - - if (user_access("administer users")) { - $output .= form_item(t("Administration"), l(t("edit account"), "admin/user/edit/$account->uid")); + if ($uid == 0) { + if ($user->uid) { + print theme('page', theme('user_profile', $user), $user->name); } + else { + $output = user_login(); + if (variable_get("user_register", 1)) { + $output .= user_register(); + } + $output .= user_pass(); - print theme('page', $output, $account->name); + print theme('page', $output, t("User login")); + } } else { - $output = user_login(); - if (variable_get("user_register", 1)) { - $output .= user_register(); + if ($account = user_load(array('uid' => $uid, "status" => 1))) { + print theme('page', theme('user_profile', $account), $account->name); + } + else { + drupal_not_found(); } - $output .= user_pass(); - - print theme('page', $output, t("User login")); } } @@ -1124,6 +1198,20 @@ function user_settings() { $group .= form_textarea(t("Body of password recovery e-mail"), "user_mail_pass_body", _user_mail_text("pass_body"), 70, 10, t("Customize the body of the forgotten password e-mail.") ." ". t("Available variables are:") ." %username, %site, %password, %uri, %uri_brief, %mailto, %login_uri, %edit_uri."); $output .= form_group(t("User email settings"), $group); + // picture settings: + if (!file_check_directory(file_create_path(variable_get('user_picture_path', 'pictures')))) { + $error = theme('error', t('The picture directory does not exist, or is not writable.')); + } + + $group = form_radios(t('Picture support'), 'user_pictures', variable_get('user_pictures', 0), array(t('Disabled'), t('Enabled')), t('Enable picture support.')); + $group .= form_textfield(t("Picture image path"), 'user_picture_path', variable_get('user_picture_path', "pictures"), 45, 255, t("Subdirectory in the directory '%dir' where pictures will be stored.", array('%dir' => variable_get('file_directory_path', 'files') . FILE_SEPARATOR)) . $error); + $group .= form_textfield(t('Default picture'), 'user_picture_default', variable_get('user_picture_default', ''), 45, 255, t('URL of picture to display for users with no custom picture selected. Leave blank for none.')); + $group .= form_textfield(t("Picture maximum dimensions"), 'user_picture_dimensions', variable_get('user_picture_dimensions', "85x85"), 10, 10, t("Maximum dimensions for pictures.")); + $group .= form_textfield(t("Picture maximum file size"), 'user_picture_file_size', variable_get('user_picture_file_size', "30"), 10, 10, t("Maximum file size for pictures, in kB.")); + $group .= form_textarea(t("Picture guidelines"), 'user_picture_guidelines', variable_get('user_picture_guidelines', ''), 70, 4, t("This text is displayed at the picture upload form in addition to the default guidelines. It's useful for helping or instructing your users.")); + + $output .= form_group(t('Pictures'), $group); + // "Who's online" block settings $period = drupal_map_assoc(array(30, 60, 120, 180, 300, 600, 900, 1800, 2700, 3600, 5400, 7200, 10800, 21600, 43200, 86400), "format_interval"); $group = form_select(t("User activity"), "user_block_seconds_online", variable_get("user_block_seconds_online", 900), $period, t("Affects \"Who's online\" block. A user is considered online for this long after they have last viewed a page.")); @@ -1270,7 +1358,7 @@ function user_admin_perm($edit = array()) { ** Compile permission array: */ - $perms = module_invoke_all("perm"); + $perms = module_invoke_all('perm'); asort($perms); /* @@ -1376,7 +1464,7 @@ function user_admin_edit($edit = array()) { if ($op == t("Save account")) { foreach (module_list() as $module) { if (module_hook($module, 'user')) { - $result = module_invoke($module, 'user', "edit_validate", $edit, $account); + $result = module_invoke($module, 'user', 'validate', $edit, $account); } if (is_array($result)) { $data = array_merge($data, $result); @@ -1401,6 +1489,14 @@ function user_admin_edit($edit = array()) { $error = t("The e-mail address '%s' is already taken.", array("%s" => $edit['mail'])); } + /* + ** If required, validate the picture. + */ + + if ($file = file_check_upload('picture')) { + $error = user_validate_picture($file, $edit, $account); + } + /* ** If required, check that proposed passwords match. If so, ** add new password to $edit. @@ -1429,7 +1525,7 @@ function user_admin_edit($edit = array()) { db_query("DELETE FROM {users} WHERE uid = %d", $account->uid); db_query("DELETE FROM {authmap} WHERE uid = %d", $account->uid); drupal_set_message(t("the account has been deleted.")); - module_invoke_all('user', "delete", $account, $user); + module_invoke_all('user', 'delete', $account, $user); } else { $error = t("Failed to delete account: the account has to be blocked first."); @@ -1445,14 +1541,24 @@ function user_admin_edit($edit = array()) { ** Display user form: */ - $output .= form_item(t("User ID"), $account->uid); - $output .= form_textfield(t("Username"), 'name', $account->name, 30, 55, t("Your full name or your preferred username: only letters, numbers and spaces are allowed.")); - $output .= form_textfield(t("E-mail address"), "mail", $account->mail, 30, 55, t("Insert a valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.")); - $output .= form_item(t("Password"), " ", t("Enter a new password twice if you want to change the current password for this user or leave it blank if you are happy with the current password.")); - $output .= form_radios(t("Status"), "status", $account->status, array(t("Blocked"), t("Active"))); - $output .= form_radios(t("Role"), "rid", $account->rid, user_roles(1)); + $group = form_item(t("User ID"), $account->uid); + $group .= form_textfield(t("Username"), 'name', $account->name, 30, 55, t("Your full name or your preferred username: only letters, numbers and spaces are allowed.")); + $group .= form_textfield(t("E-mail address"), "mail", $account->mail, 30, 55, t("Insert a valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.")); + $group .= form_item(t("Password"), " ", t("Enter a new password twice if you want to change the current password for this user or leave it blank if you are happy with the current password.")); + $group .= form_radios(t("Status"), "status", $account->status, array(t("Blocked"), t("Active"))); + $group .= form_radios(t("Role"), "rid", $account->rid, user_roles(1)); + + $output = form_group(t('Account information'), $group); + + if (variable_get('user_pictures', 0)) { + $group = ''; + if (file_exists($account->picture)) { + $group .= ''; + } + $group .= form_file(t('Upload picture or picture'), 'picture', 48, t("Maximum dimensions are %dimensions and the maximum size is %size kB.", array("%dimensions" => variable_get('user_picture_dimensions', "85x85"), "%size" => variable_get('user_picture_file_size', "30")))); + $output .= form_group(t('Picture'), $group); + } - $output = form_group(t('Account information'), $output); $output .= _user_profile($edit, $account); $output .= form_submit(t("Save account")); @@ -1473,16 +1579,16 @@ function user_admin_account() { array("data" => t("username"), "field" => "u.name"), array("data" => t("status"), "field" => "u.status"), array("data" => t("role"), "field" => "u.rid"), - array("data" => t("last access"), "field" => "u.timestamp", "sort" => "desc"), + array("data" => t("last access"), "field" => "u.changed", "sort" => "desc"), t("operations") ); - $sql = "SELECT u.uid, u.name, u.status, u.timestamp, r.name AS rolename FROM {role} r INNER JOIN {users} u ON r.rid = u.rid WHERE uid != 0"; + $sql = "SELECT u.uid, u.name, u.status, u.changed, r.name AS rolename FROM {role} r INNER JOIN {users} u ON r.rid = u.rid WHERE uid != 0"; $sql .= tablesort_sql($header); $result = pager_query($sql, 50); $status = array(t("blocked"), t("active")); while ($account = db_fetch_object($result)) { - $rows[] = array($account->uid, format_name($account), $status[$account->status], $account->rolename, format_date($account->timestamp, "small"), l(t("edit account"), "admin/user/edit/$account->uid")); + $rows[] = array($account->uid, format_name($account), $status[$account->status], $account->rolename, format_date($account->changed, "small"), l(t("edit account"), "admin/user/edit/$account->uid")); } $pager = theme("pager", NULL, 50, 0, tablesort_pager()); @@ -1692,18 +1798,14 @@ function user_help($section = "admin/help#user") { function julia_user(\$type, \$edit, &\$user) { // What type of registration action are we taking? switch (\$type) { - case t(\"view_public\"): - // when others look at user data + case t(\"view\"): return form_item(\"Favorite Ingredient\", \$user->julia_favingredient); - case t(\"view_private\"): - // when user tries to view his own user page. - return form_item(\"Favorite Ingredient\", \$user->julia_favingredient); - case t(\"edit_form\"): + case t(\"edit\"): // when user tries to edit his own user page. return form_textfield(\"Favorite Ingredient\", \"julia_favingredient\", \$user->julia_favingredient, 50, 65, \"Tell everyone your secret spice\"); - case t(\"edit_validate\"): // Make sure the data they edited is \"valid\". + case t(\"validate\"): // Make sure the data they edited is \"valid\". return user_save(\$user, array(\"julia_favingredient\" => \$edit[\"julia_favingredient\"])); } } diff --git a/modules/user/user.module b/modules/user/user.module index 68d25921a2d..1dbc33dafe4 100644 --- a/modules/user/user.module +++ b/modules/user/user.module @@ -78,12 +78,13 @@ function user_save($account, $array = array()) { $query .= "data = '%s', "; $v[] = serialize($data); - db_query("UPDATE {users} SET $query timestamp = %d WHERE uid = %d", array_merge($v, array(time(), $account->uid))); + db_query("UPDATE {users} SET $query changed = %d WHERE uid = %d", array_merge($v, array(time(), $account->uid))); $user = user_load(array('uid' => $account->uid)); } else { - $array['timestamp'] = time(); + $array['created'] = time(); + $array['changed'] = time(); $array['uid'] = db_next_id("{users}_uid"); foreach ($array as $key => $value) { @@ -112,11 +113,11 @@ function user_save($account, $array = array()) { $user = user_load(array('name' => $array['name'])); - module_invoke_all('user', "insert", $array, $user); + module_invoke_all('user', 'insert', $array, $user); } foreach ($array as $key => $value) { - if (substr($key, 0, 4) == "auth") { + if (substr($key, 0, 4) == 'auth') { $authmaps[$key] = $value; } } @@ -136,7 +137,7 @@ function user_validate_name($name) { if (!$name) return t("You must enter a username."); if (substr($name, 0, 1) == ' ') return t("The username cannot begin with a space."); if (substr($name, -1) == ' ') return t("The username cannot end with a space."); - if (ereg(" ", $name)) return t("The username cannot contain multiple spaces in a row."); + if (ereg(' ', $name)) return t("The username cannot contain multiple spaces in a row."); if (ereg('[^ [:alnum:]@_.-]', $name)) return t("The username contains an illegal character."); if (ereg('@', $name) && !eregi('@([0-9a-z](-?[0-9a-z])*.)+[a-z]{2}([zmuvtg]|fo|me)?$', $name)) return t("The username is not a valid authentication ID."); if (strlen($name) > 56) return t("The username '%name' is too long: it must be less than 56 characters.", array("%name" => $name)); @@ -149,6 +150,35 @@ function user_validate_mail($mail) { } } +function user_validate_picture($file, &$edit, $user) { + + // initialize the picture: + $edit['picture'] = $user->picture; + + // check that uploaded file is an image, with a maximum file size and maximum height/width + $extension = strtolower(strrchr($file->name, ".")); + $size = getimagesize($file->path); + list($maxwidth, $maxheight) = explode("x", variable_get('user_picture_dimensions', "85x85")); + + if ((!in_array($size[2], array(1, 2, 3))) || (!in_array($extension, array(".gif", ".jpg", ".png", ".jpeg")))) { + $error = t("The uploaded file was not an image."); + } + else if ($file->size > (variable_get('user_picture_file_size', "30") * 1000)) { + $error = t("The uploaded image is too large; the maximum file size is %a kB.", array("%a" => variable_get('user_picture_file_size', "30"))); + } + else if ($size[0] > $maxwidth || $size[1] > $maxheight) { + $error = t("The uploaded image is too large; the maximum dimensions are %a pixels.", array("%a" => variable_get('user_picture_dimensions', "85x85"))); + } + else if ($file = file_save_upload('picture', variable_get('user_picture_path', "pictures") . FILE_SEPARATOR .'picture-'. $user->uid . $extension, 1)) { + $edit['picture'] = $file->path; + } + else { + $error = t("Failed to upload the picture image; the '%directory' directory doesn't exist.", array("%directory" => variable_get('user_picture_path', "pictures"))); + } + + return $error; +} + function user_validate_authmap($account, $authname, $module) { $result = db_query("SELECT COUNT(*) from {authmap} WHERE uid != %d AND authname = '%s'", $account->uid, $authname); if (db_result($result) > 0) { @@ -281,7 +311,7 @@ function user_fields() { } else { // Make sure we return the default fields at least - $fields = array('uid', 'name', 'pass', "mail", "mode", "sort", "threshold", "theme", "signature", "timestamp", "status", "timezone", "language", "init", "data", "rid"); + $fields = array('uid', 'name', 'pass', "mail", "picture", "mode", "sort", "threshold", "theme", "signature", "created", "changed", "status", "timezone", "language", "init", "data", "rid"); } } @@ -428,6 +458,42 @@ function user_block($op = "list", $delta = 0) { } } +function theme_user_picture($account) { + if (variable_get('user_pictures', 0)) { + if ($account->picture && file_exists($account->picture)) { + $picture = file_create_url($account->picture); + } + else if (variable_get('user_picture_default', '')) { + $picture = variable_get('user_picture_default', ''); + } + + if ($picture) { + $picture = "\"" $account->name ? $account->name : t(variable_get("anonymous", "Anonymous")))) . "\" />"; + if ($account->uid) { + $picture = l($picture, "user/view/$account->uid", array("title" => t("View user profile."))); + } + + return "
$picture
"; + } + } +} + +function theme_user_profile($account) { + $output = "
\n"; + $output .= theme('user_picture', $account); + $output .= form_item(t('Name'), $account->name); + $output .= implode("\n", module_invoke_all('user', 'view', '', $account)); + $output .= form_item(t('Member for'), format_interval(time() - $account->created)); + + if (user_access("administer users")) { + $output .= form_item(t("Administration"), l(t("edit account"), "admin/user/edit/$account->uid")); + } + + $output .= "
\n"; + + return $output; +} + function theme_user_list($items, $title = NULL) { return theme("item_list", $items, $title); } @@ -595,7 +661,7 @@ function user_login($edit = array(), $msg = "") { watchdog('user', "session opened for '$user->name'"); // update the user table timestamp noting user has logged in - db_query("UPDATE {users} SET timestamp = '%d' WHERE uid = '%s'", time(), $user->uid); + db_query("UPDATE {users} SET changed = '%d' WHERE uid = '%s'", time(), $user->uid); user_module_invoke("login", $edit, $user); @@ -685,7 +751,7 @@ function user_logout() { */ session_destroy(); - module_invoke_all('user', "logout", NULL, $user); + module_invoke_all('user', 'logout', NULL, $user); unset($user); } @@ -884,7 +950,15 @@ function user_edit($edit = array()) { else if ($edit['mail'] && db_num_rows(db_query("SELECT uid FROM {users} WHERE uid != '$user->uid' AND LOWER(mail) = LOWER('%s')", $edit['mail'])) > 0) { $error = t("The e-mail address '%s' is already taken.", array("%s" => $edit['mail'])); } - else if ($user->uid) { + else { + /* + ** If required, validate the picture. + */ + + if ($file = file_check_upload('picture')) { + $error = user_validate_picture($file, $edit, $user); + } + /* ** If required, check that proposed passwords match. If so, ** add new password to $edit. @@ -922,7 +996,7 @@ function user_edit($edit = array()) { foreach (module_list() as $module) { if (module_hook($module, 'user')) { - $result = module_invoke($module, 'user', "edit_validate", $edit, $user); + $result = module_invoke($module, 'user', 'validate', $edit, $user); } if (is_array($result)) { $data = array_merge($data, $result); @@ -940,7 +1014,7 @@ function user_edit($edit = array()) { $user = user_save($user, array_merge($edit, $data)); - drupal_set_message(t("your user information changes have been saved.")); + drupal_set_message(t('your user information changes have been saved.')); } } } @@ -953,15 +1027,25 @@ function user_edit($edit = array()) { $edit = object2array($user); } - $output = form_textfield(t("Username"), 'name', $edit['name'], 30, 55, t("Your full name or your preferred username: only letters, numbers and spaces are allowed.")); - $output .= form_textfield(t("E-mail address"), "mail", $edit['mail'], 30, 55, t("Insert a valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.")); - $output .= form_item(t("Password"), " ", t("Enter your new password twice if you want to change your current password or leave it blank if you are happy with your current password.")); - $output = form_group(t('Account information'), $output); + $group = form_textfield(t("Username"), 'name', $edit['name'], 30, 55, t("Your full name or your preferred username: only letters, numbers and spaces are allowed.")); + $group .= form_textfield(t("E-mail address"), "mail", $edit['mail'], 30, 55, t("Insert a valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.")); + $group .= form_item(t("Password"), " ", t("Enter your new password twice if you want to change your current password or leave it blank if you are happy with your current password.")); + $output = form_group(t('Account information'), $group); + + if (variable_get('user_pictures', 0)) { + $group = ''; + if (file_exists($user->picture)) { + $group .= ''; + } + $group .= form_file(t('Upload picture or picture'), 'picture', 48, t("Your virtual face or picture. Maximum dimensions are %dimensions and the maximum size is %size kB.", array("%dimensions" => variable_get('user_picture_dimensions', "85x85"), "%size" => variable_get('user_picture_file_size', "30"))) ." ". variable_get('user_picture_guidelines', '')); + $output .= form_group(t('Picture'), $group); + } + $output .= _user_profile($edit, $user); $output .= form_submit(t("Save user information")); $output = form($output, "post", 0, array("enctype" => "multipart/form-data")); - // the "enctype" attribute is required to upload files such as avatars + // the "enctype" attribute is required to upload files such as pictures } else { $output = user_login(); @@ -973,7 +1057,7 @@ function user_edit($edit = array()) { function _user_profile($edit, $account) { foreach (module_list() as $module) { - if ($data = module_invoke($module, 'user', 'edit_form', $edit, $account)) { + if ($data = module_invoke($module, 'user', 'edit', $edit, $account)) { foreach ($data as $title => $form) { $groups[$title] .= $form; } @@ -991,37 +1075,27 @@ function _user_profile($edit, $account) { function user_view($uid = 0) { global $user; - if (!$uid) { - $uid = $user->uid; - } - - if ($user->uid && $user->uid == $uid) { - $output = form_item(t("Name"), "$user->name ($user->init)"); - $output .= form_item(t("E-mail address"), $user->mail, t("Please note that only you can see your own e-mail address - it is not publicly visible.")); - - $output .= implode("\n", module_invoke_all('user', "view_private", "", $user)); - - print theme('page', $output, $user->name); - } - else if ($uid && $account = user_load(array('uid' => $uid, "status" => 1))) { - $output = form_item(t("Name"), $account->name); - - $output .= implode("\n", module_invoke_all('user', "view_public", "", $account)); - - if (user_access("administer users")) { - $output .= form_item(t("Administration"), l(t("edit account"), "admin/user/edit/$account->uid")); + if ($uid == 0) { + if ($user->uid) { + print theme('page', theme('user_profile', $user), $user->name); } + else { + $output = user_login(); + if (variable_get("user_register", 1)) { + $output .= user_register(); + } + $output .= user_pass(); - print theme('page', $output, $account->name); + print theme('page', $output, t("User login")); + } } else { - $output = user_login(); - if (variable_get("user_register", 1)) { - $output .= user_register(); + if ($account = user_load(array('uid' => $uid, "status" => 1))) { + print theme('page', theme('user_profile', $account), $account->name); + } + else { + drupal_not_found(); } - $output .= user_pass(); - - print theme('page', $output, t("User login")); } } @@ -1124,6 +1198,20 @@ function user_settings() { $group .= form_textarea(t("Body of password recovery e-mail"), "user_mail_pass_body", _user_mail_text("pass_body"), 70, 10, t("Customize the body of the forgotten password e-mail.") ." ". t("Available variables are:") ." %username, %site, %password, %uri, %uri_brief, %mailto, %login_uri, %edit_uri."); $output .= form_group(t("User email settings"), $group); + // picture settings: + if (!file_check_directory(file_create_path(variable_get('user_picture_path', 'pictures')))) { + $error = theme('error', t('The picture directory does not exist, or is not writable.')); + } + + $group = form_radios(t('Picture support'), 'user_pictures', variable_get('user_pictures', 0), array(t('Disabled'), t('Enabled')), t('Enable picture support.')); + $group .= form_textfield(t("Picture image path"), 'user_picture_path', variable_get('user_picture_path', "pictures"), 45, 255, t("Subdirectory in the directory '%dir' where pictures will be stored.", array('%dir' => variable_get('file_directory_path', 'files') . FILE_SEPARATOR)) . $error); + $group .= form_textfield(t('Default picture'), 'user_picture_default', variable_get('user_picture_default', ''), 45, 255, t('URL of picture to display for users with no custom picture selected. Leave blank for none.')); + $group .= form_textfield(t("Picture maximum dimensions"), 'user_picture_dimensions', variable_get('user_picture_dimensions', "85x85"), 10, 10, t("Maximum dimensions for pictures.")); + $group .= form_textfield(t("Picture maximum file size"), 'user_picture_file_size', variable_get('user_picture_file_size', "30"), 10, 10, t("Maximum file size for pictures, in kB.")); + $group .= form_textarea(t("Picture guidelines"), 'user_picture_guidelines', variable_get('user_picture_guidelines', ''), 70, 4, t("This text is displayed at the picture upload form in addition to the default guidelines. It's useful for helping or instructing your users.")); + + $output .= form_group(t('Pictures'), $group); + // "Who's online" block settings $period = drupal_map_assoc(array(30, 60, 120, 180, 300, 600, 900, 1800, 2700, 3600, 5400, 7200, 10800, 21600, 43200, 86400), "format_interval"); $group = form_select(t("User activity"), "user_block_seconds_online", variable_get("user_block_seconds_online", 900), $period, t("Affects \"Who's online\" block. A user is considered online for this long after they have last viewed a page.")); @@ -1270,7 +1358,7 @@ function user_admin_perm($edit = array()) { ** Compile permission array: */ - $perms = module_invoke_all("perm"); + $perms = module_invoke_all('perm'); asort($perms); /* @@ -1376,7 +1464,7 @@ function user_admin_edit($edit = array()) { if ($op == t("Save account")) { foreach (module_list() as $module) { if (module_hook($module, 'user')) { - $result = module_invoke($module, 'user', "edit_validate", $edit, $account); + $result = module_invoke($module, 'user', 'validate', $edit, $account); } if (is_array($result)) { $data = array_merge($data, $result); @@ -1401,6 +1489,14 @@ function user_admin_edit($edit = array()) { $error = t("The e-mail address '%s' is already taken.", array("%s" => $edit['mail'])); } + /* + ** If required, validate the picture. + */ + + if ($file = file_check_upload('picture')) { + $error = user_validate_picture($file, $edit, $account); + } + /* ** If required, check that proposed passwords match. If so, ** add new password to $edit. @@ -1429,7 +1525,7 @@ function user_admin_edit($edit = array()) { db_query("DELETE FROM {users} WHERE uid = %d", $account->uid); db_query("DELETE FROM {authmap} WHERE uid = %d", $account->uid); drupal_set_message(t("the account has been deleted.")); - module_invoke_all('user', "delete", $account, $user); + module_invoke_all('user', 'delete', $account, $user); } else { $error = t("Failed to delete account: the account has to be blocked first."); @@ -1445,14 +1541,24 @@ function user_admin_edit($edit = array()) { ** Display user form: */ - $output .= form_item(t("User ID"), $account->uid); - $output .= form_textfield(t("Username"), 'name', $account->name, 30, 55, t("Your full name or your preferred username: only letters, numbers and spaces are allowed.")); - $output .= form_textfield(t("E-mail address"), "mail", $account->mail, 30, 55, t("Insert a valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.")); - $output .= form_item(t("Password"), " ", t("Enter a new password twice if you want to change the current password for this user or leave it blank if you are happy with the current password.")); - $output .= form_radios(t("Status"), "status", $account->status, array(t("Blocked"), t("Active"))); - $output .= form_radios(t("Role"), "rid", $account->rid, user_roles(1)); + $group = form_item(t("User ID"), $account->uid); + $group .= form_textfield(t("Username"), 'name', $account->name, 30, 55, t("Your full name or your preferred username: only letters, numbers and spaces are allowed.")); + $group .= form_textfield(t("E-mail address"), "mail", $account->mail, 30, 55, t("Insert a valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.")); + $group .= form_item(t("Password"), " ", t("Enter a new password twice if you want to change the current password for this user or leave it blank if you are happy with the current password.")); + $group .= form_radios(t("Status"), "status", $account->status, array(t("Blocked"), t("Active"))); + $group .= form_radios(t("Role"), "rid", $account->rid, user_roles(1)); + + $output = form_group(t('Account information'), $group); + + if (variable_get('user_pictures', 0)) { + $group = ''; + if (file_exists($account->picture)) { + $group .= ''; + } + $group .= form_file(t('Upload picture or picture'), 'picture', 48, t("Maximum dimensions are %dimensions and the maximum size is %size kB.", array("%dimensions" => variable_get('user_picture_dimensions', "85x85"), "%size" => variable_get('user_picture_file_size', "30")))); + $output .= form_group(t('Picture'), $group); + } - $output = form_group(t('Account information'), $output); $output .= _user_profile($edit, $account); $output .= form_submit(t("Save account")); @@ -1473,16 +1579,16 @@ function user_admin_account() { array("data" => t("username"), "field" => "u.name"), array("data" => t("status"), "field" => "u.status"), array("data" => t("role"), "field" => "u.rid"), - array("data" => t("last access"), "field" => "u.timestamp", "sort" => "desc"), + array("data" => t("last access"), "field" => "u.changed", "sort" => "desc"), t("operations") ); - $sql = "SELECT u.uid, u.name, u.status, u.timestamp, r.name AS rolename FROM {role} r INNER JOIN {users} u ON r.rid = u.rid WHERE uid != 0"; + $sql = "SELECT u.uid, u.name, u.status, u.changed, r.name AS rolename FROM {role} r INNER JOIN {users} u ON r.rid = u.rid WHERE uid != 0"; $sql .= tablesort_sql($header); $result = pager_query($sql, 50); $status = array(t("blocked"), t("active")); while ($account = db_fetch_object($result)) { - $rows[] = array($account->uid, format_name($account), $status[$account->status], $account->rolename, format_date($account->timestamp, "small"), l(t("edit account"), "admin/user/edit/$account->uid")); + $rows[] = array($account->uid, format_name($account), $status[$account->status], $account->rolename, format_date($account->changed, "small"), l(t("edit account"), "admin/user/edit/$account->uid")); } $pager = theme("pager", NULL, 50, 0, tablesort_pager()); @@ -1692,18 +1798,14 @@ function user_help($section = "admin/help#user") { function julia_user(\$type, \$edit, &\$user) { // What type of registration action are we taking? switch (\$type) { - case t(\"view_public\"): - // when others look at user data + case t(\"view\"): return form_item(\"Favorite Ingredient\", \$user->julia_favingredient); - case t(\"view_private\"): - // when user tries to view his own user page. - return form_item(\"Favorite Ingredient\", \$user->julia_favingredient); - case t(\"edit_form\"): + case t(\"edit\"): // when user tries to edit his own user page. return form_textfield(\"Favorite Ingredient\", \"julia_favingredient\", \$user->julia_favingredient, 50, 65, \"Tell everyone your secret spice\"); - case t(\"edit_validate\"): // Make sure the data they edited is \"valid\". + case t(\"validate\"): // Make sure the data they edited is \"valid\". return user_save(\$user, array(\"julia_favingredient\" => \$edit[\"julia_favingredient\"])); } } diff --git a/themes/xtemplate/default/xtemplate.css b/themes/xtemplate/default/xtemplate.css index cc42447dcff..fcf8d4f0855 100644 --- a/themes/xtemplate/default/xtemplate.css +++ b/themes/xtemplate/default/xtemplate.css @@ -222,7 +222,7 @@ table { font-size: 0.8em; padding: 1.5em; } -.node .avatar { +.node .picture { border: 1px solid #ddd; float: right; margin: 0.5em; @@ -242,7 +242,7 @@ table { float: right; color: red; } -.comment .avatar { +.comment .picture { border: 1px solid #abc; float: right; margin: 0.5em; diff --git a/themes/xtemplate/default/xtemplate.xtmpl b/themes/xtemplate/default/xtemplate.xtmpl index b6c74d22bbc..a1e0e72ac74 100644 --- a/themes/xtemplate/default/xtemplate.xtmpl +++ b/themes/xtemplate/default/xtemplate.xtmpl @@ -56,9 +56,9 @@
- -
{avatar}
- + + {picture} +

{title}

@@ -75,9 +75,9 @@
- -
{avatar}
- + + {picture} +

{title}

{new}
{content}
diff --git a/themes/xtemplate/pushbutton/xtemplate.css b/themes/xtemplate/pushbutton/xtemplate.css index dd06bc2b931..e3c72a2d4d9 100644 --- a/themes/xtemplate/pushbutton/xtemplate.css +++ b/themes/xtemplate/pushbutton/xtemplate.css @@ -312,7 +312,7 @@ table#footer-links { font-size: 0.83em; padding: 1.5em; } -.node .avatar { +.node .picture { border: 1px solid #fff; float: right; margin: 0.5em; @@ -334,7 +334,7 @@ table#footer-links { float: right; color: red; } -.comment .avatar { +.comment .picture { border: 1px solid #fff; float: right; margin: 0.5em; diff --git a/themes/xtemplate/pushbutton/xtemplate.xtmpl b/themes/xtemplate/pushbutton/xtemplate.xtmpl index f2eccd4c1bf..df01933c528 100644 --- a/themes/xtemplate/pushbutton/xtemplate.xtmpl +++ b/themes/xtemplate/pushbutton/xtemplate.xtmpl @@ -59,9 +59,9 @@
- -
{avatar}
- + + {picture} +

{title}

@@ -78,9 +78,9 @@
- -
{avatar}
- + +
{picture}
+

{title}

{new}
{content}
diff --git a/themes/xtemplate/xtemplate.theme b/themes/xtemplate/xtemplate.theme index ac3e43a1447..91069870743 100644 --- a/themes/xtemplate/xtemplate.theme +++ b/themes/xtemplate/xtemplate.theme @@ -32,7 +32,8 @@ function xtemplate_settings() { $group .= form_radios(t('Search box'), 'xtemplate_search_box', variable_get('xtemplate_search_box', 0), array(t('Disabled'), t('Enabled')), t('Show a search box in the upper right corner.')); $output .= form_group(t('Header settings'), $group); - $group = form_checkbox(t('Display avatars with posts'), 'xtemplate_avatar_node', 1, variable_get('xtemplate_avatar_node', 0), t('Display individualized pictures identifying users with posts they start.')) . form_checkbox(t('Display avatars with comments'), 'xtemplate_avatar_comment', 1, variable_get('xtemplate_avatar_comment', 0), t('Display individualized pictures identifying users with their comments.')) . form_textfield(t('Default avatar'), 'xtemplate_avatar_default', variable_get('xtemplate_avatar_default', ''), 70, 300, t('URL of avatar to display for users with no custom avatar selected. Leave blank for none.')); + $group = form_checkbox(t('Display pictures with posts'), 'xtemplate_picture_node', 1, variable_get('xtemplate_picture_node', 0), t('Display individualized pictures identifying users with posts they start.')); + $gourp .= form_checkbox(t('Display pictures with comments'), 'xtemplate_picture_comment', 1, variable_get('xtemplate_picture_comment', 0), t('Display individualized pictures identifying users with their comments.')); $output .= form_group(t('Avatar settings'), $group); return $output; @@ -69,22 +70,9 @@ function xtemplate_node($node, $main = 0, $page = 0) { $xtemplate->template->parse("node.title"); } - if (module_exist("profile") && variable_get("xtemplate_avatar_node", 0)) { - $avatar = $node->profile_avatar; - if (empty($avatar) || !file_exists($avatar)) { - $avatar = variable_get("xtemplate_avatar_default", ""); - } - else { - $avatar = file_create_url($avatar); - } - if ($avatar) { - $avatar = "\"" $node->name ? $node->name : t(variable_get("anonymous", "Anonymous")))) . "\" />"; - if ($node->uid) { - $avatar = l($avatar, "user/view/$node->uid", array("title" => t("View user profile."))); - } - $xtemplate->template->assign("avatar", $avatar); - $xtemplate->template->parse("node.avatar"); - } + if ($picture = theme('user_picture', $node)) { + $xtemplate->template->assign("picture", $picture); + $xtemplate->template->parse("node.picture"); } if (module_exist("taxonomy") && ($taxonomy = taxonomy_link("taxonomy terms", $node))) { @@ -121,22 +109,9 @@ function xtemplate_comment($comment, $links = 0) { $xtemplate->template->parse("comment.new"); } - if (module_exist("profile") && variable_get("xtemplate_avatar_comment", 0)) { - $avatar = $comment->profile_avatar; - if (empty($avatar) || !file_exists($avatar)) { - $avatar = variable_get("xtemplate_avatar_default", ""); - } - else { - $avatar = file_create_url($avatar); - } - if ($avatar) { - $avatar = "\"" $comment->name ? $comment->name : t(variable_get("anonymous", "Anonymous")))) . "\" />"; - if ($comment->uid) { - $avatar = l($avatar, "user/view/$comment->uid", array("title" => t("View user profile."))); - } - $xtemplate->template->assign("avatar", $avatar); - $xtemplate->template->parse("comment.avatar"); - } + if ($picture = theme('user_picture', $comment)) { + $xtemplate->template->assign("picture", $picture); + $xtemplate->template->parse("comment.picture"); } if ($links) {