diff --git a/checkin_notes b/checkin_notes index 1dc966d3f3..e5ed7dfe04 100755 --- a/checkin_notes +++ b/checkin_notes @@ -8593,3 +8593,35 @@ David 20 Dec 2003 client/win/ wingui_mainwindow.cpp,h + +David 20 Dec 2003 + - compute recent average credit correctly + - compute "activity" for questions in a reasonable way: + the number of times per day this question has been asked + - default sort order for questions is by descending activity + - added fulltext indices on profile.response1 and profile.response2 + - added text search of profiles to web interface + - link to list of a user's posts from their user page + - generate UOD page even if already there + - clean up some PHP code: + use $foo->bar, not $foo['bar'] + indent by 4 spaces + + db/ + constraints.sql + schema.sql + html_ops/ + gallery.inc + update_forum_activities.php + html_user/ + profile_menu.php + user.inc + util.inc + profile_search_action.php (new) + forum/ + forum.inc + forum.php + text_search_action.php + user_posts.php (new) + sched/ + sched_util.C diff --git a/db/constraints.sql b/db/constraints.sql index bb8277c366..af5c16e096 100644 --- a/db/constraints.sql +++ b/db/constraints.sql @@ -86,6 +86,7 @@ alter table host -- db_dump.C alter table profile + add fulltext index profile_reponse(response1, reponse2), add unique profile_userid(userid); alter table subscriptions @@ -95,4 +96,6 @@ alter table thread add fulltext index thread_title(title); alter table post + add index post_user (user), + add index post_thread (thread), add fulltext index post_content(content); diff --git a/db/schema.sql b/db/schema.sql index d802652411..399ec8a57f 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -287,7 +287,7 @@ create table forum ( primary key (id) ); --- threads in a topic +-- threads in a topic (or questions) -- create table thread ( id integer not null auto_increment, @@ -300,8 +300,9 @@ create table thread ( -- number of times this has been viewed replies integer not null, -- number of postings in thread - activity integer not null, - -- not used?? should remove references + activity double not null, + -- for questions: number of askers / time since asked + (set periodically by update_forum_activity.php) sufferers integer not null, -- in help desk: # people who indicated they had same problem create_time integer not null, @@ -309,7 +310,7 @@ create table thread ( primary key (id) ); --- postings in a thread. +-- postings in a thread (or answers) -- Each thread has an initial post -- create table post ( diff --git a/html/forum/forum.inc b/html/forum/forum.inc index 92ca9f12e9..b791c98bfc 100644 --- a/html/forum/forum.inc +++ b/html/forum/forum.inc @@ -21,8 +21,7 @@ $forum_sort_styles['replies-most'] = "Most posts first"; $faq_sort_styles['create_time'] = "Most recent question first"; $faq_sort_styles['timestamp'] = "Most recent answer first"; -$faq_sort_styles['sufferers'] = "Most often asked first"; -$faq_sort_styles['activity'] = "Highest score first"; +$faq_sort_styles['activity'] = "Most often asked first"; $answer_sort_styles['score'] = "Highest score first"; $answer_sort_styles['timestamp'] = "Most recent first"; @@ -454,4 +453,63 @@ function show_forum_title($forum=NULL, $thread=NULL, $helpdesk=false) { echo "

\n"; } +// show a thread with its context (e.g. for search results) +// +function show_thread($thread, $n) { + $forum = getForum($thread->forum); + $category = getCategory($forum->category); + $first_post = getFirstPost($thread->id); + $title = stripslashes($thread->title); + $where = $category->is_helpdesk?"Questions and answers":"Message boards"; + $top_url = $category->is_helpdesk?"help_desk.php":"index.php"; + $excerpt = sub_sentence(stripslashes($first_post->content), ' ', EXCERPT_LENGTH, true); + $posted = time_diff_str($thread->create_time, time()); + $last = time_diff_str($thread->timestamp, time()); + $m = $n%2; + echo " + + + $n) Posted $posted +
+ Last response $last + + + $where : $category->name : + id>$forum->title : + id>$title +
+ $excerpt + + + "; +} + +// show a post with its context (e.g. for search results) +// +function show_post2($post, $n) { + $thread = getThread($post->thread); + $forum = getForum($thread->forum); + $category = getCategory($forum->category); + $where = $category->is_helpdesk?"Questions and answers":"Message boards"; + $top_url = $category->is_helpdesk?"help_desk.php":"index.php"; + $content = nl2br(stripslashes($post->content)); + $when = time_diff_str($post->timestamp, time()); + $user = lookup_user_id($post->user); + $title = stripslashes($thread->title); + $m = $n%2; + echo " + + + $n) $where : $category->name : + id>$forum->title : + id>$title +
+ Posted $when by $user->name +
+ $content + + + "; +} + ?> diff --git a/html/forum/forum.php b/html/forum/forum.php index c6ed0469a9..3ee34e814d 100644 --- a/html/forum/forum.php +++ b/html/forum/forum.php @@ -27,7 +27,7 @@ $category = getCategory($forum->category); if ($category->is_helpdesk) { page_head('Help Desk'); $sort_style = $_GET['sort']; - if (!$sort_style) $sort_style = 'sufferers'; + if (!$sort_style) $sort_style = 'activity'; } else { page_head('Message boards : '.$forum->title); $sort_style = $_GET['sort']; @@ -85,7 +85,7 @@ while($thread = mysql_fetch_object($threads)) { $first_post = getFirstPost($thread->id); $excerpt = sub_sentence($first_post->content, ' ', EXCERPT_LENGTH, true); echo " - + id, "\">", stripslashes($thread->title), "
"; $n = ($n+1)%2; diff --git a/html/forum/text_search_action.php b/html/forum/text_search_action.php index a46006c9b7..509395ddf2 100644 --- a/html/forum/text_search_action.php +++ b/html/forum/text_search_action.php @@ -10,61 +10,6 @@ $count = 10; page_head("Search results"); -function show_thread($thread, $n) { - $forum = getForum($thread->forum); - $category = getCategory($forum->category); - $first_post = getFirstPost($thread->id); - $title = stripslashes($thread->title); - $where = $category->is_helpdesk?"Questions and answers":"Message boards"; - $top_url = $category->is_helpdesk?"help_desk.php":"index.php"; - $excerpt = sub_sentence(stripslashes($first_post->content), ' ', EXCERPT_LENGTH, true); - $posted = time_diff_str($thread->create_time, time()); - $last = time_diff_str($thread->timestamp, time()); - $m = $n%2; - echo " - - - $n) Posted $posted -
- Last response $last - - - $where : $category->name : - id>$forum->title : - id>$title -
- $excerpt - - - "; -} - -function show_post2($post, $n) { - $thread = getThread($post->thread); - $forum = getForum($thread->forum); - $category = getCategory($forum->category); - $where = $category->is_helpdesk?"Questions and answers":"Message boards"; - $top_url = $category->is_helpdesk?"help_desk.php":"index.php"; - $content = nl2br(stripslashes($post->content)); - $when = time_diff_str($post->timestamp, time()); - $user = lookup_user_id($post->user); - $title = stripslashes($thread->title); - $m = $n%2; - echo " - - - $n) $where : $category->name : - id>$forum->title : - id>$title -
- Posted $when by $user->name -
- $content - - - "; -} - if ($_GET['titles']) { echo "

Titles containing '$search_string'

\n"; $q = "select * from thread where match(title) against ('$search_string') limit $offset,$count"; diff --git a/html/forum/user_posts.php b/html/forum/user_posts.php new file mode 100644 index 0000000000..b980e82ea6 --- /dev/null +++ b/html/forum/user_posts.php @@ -0,0 +1,23 @@ +name"); +$result = mysql_query("select * from post where user=$userid order by id desc"); +$n = 1; +echo "\n"; +while($post = mysql_fetch_object($result)) { + show_post2($post, $n); + $n++; +} +echo "
\n"; +mysql_free_result($result); + +?> diff --git a/html/ops/gallery.inc b/html/ops/gallery.inc index e7a104a51f..c42439a7b7 100644 --- a/html/ops/gallery.inc +++ b/html/ops/gallery.inc @@ -5,7 +5,9 @@ require_once("../html_user/profile.inc"); require_once("../html_user/util.inc"); -// OK, so it's not quite the alphabet, but alphanumerabet is a bad variable name. +// OK, so it's not quite the alphabet, +// but alphanumerabet is a bad variable name. +// $alphabet = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9'); // Generates the html files which comprise the photo gallery. @@ -14,82 +16,93 @@ $alphabet = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P // $height: the height of the table of images. function build_picture_pages($width, $height) { - // TODO: Add support for a computer image gallery. + // TODO: Add support for a computer image gallery. - // TODO: Should we eliminate the has_picture flag? Doesn't really - // seem necessary when we're building static pages- could just use - // file_exists on the username... + // TODO: Should we eliminate the has_picture flag? Doesn't really + // seem necessary when we're building static pages- could just use + // file_exists on the username... - // TODO: Standardize "Last modified" string to a function call (util.inc). + // TODO: Standardize "Last modified" string to a function call (util.inc). - $query = "SELECT userid FROM profile WHERE has_picture = 1"; - $result = mysql_query($query); - $numIds = mysql_num_rows($result); + $query = "SELECT userid FROM profile WHERE has_picture = 1"; + $result = mysql_query($query); + $numIds = mysql_num_rows($result); - //echo "Result has $numIds rows.
"; + //echo "Result has $numIds rows.
"; - // Build an array of IDs of all users with pictures in their profiles. - while ($row = mysql_fetch_array($result, MYSQL_NUM)) { - $userIds[] = $row[0]; - } - - mysql_free_result($result); - - if (count($userIds) > 0) { - // Randomize the ordering of users. - shuffle($userIds); - } - - $numPages = ceil(count($userIds)/($width * $height)); - - // Make sure that a page is generated even when no profiles with pictures - // exist in order to avoid 404 errors from the profile_menu page. - - if ($numPages == 0) { - $numPages = 1; - } - - //echo "Generating $numPages pages.
"; - - $count = 0; - - for ($page = 1; $page <= $numPages; $page++) { - $file = "../html_user/" . PROFILE_PATH . "user_gallery_" . $page . ".html"; - $descriptor = fopen($file, "w"); - - page_head("User Picture Gallery: Page $page of $numPages", null, $descriptor); - - fwrite($descriptor, "

User Profile Pictures

Last updated " . pretty_time_str(time()) . "\n

Browse the user profiles by picture. Only user profiles with pictures are listed here."); - - fwrite($descriptor, "\n"); - - for ($row = 0; $row < $height; $row++) { - fwrite($descriptor, ""); - for ($col = 0; $col < $width; $col++) { - if ($count < $numIds) { - - fwrite($descriptor, ""); - $count++; - } - } - fwrite($descriptor, "\n"); - if ($count == $numIds) { - break; - } + // Build an array of IDs of all users with pictures in their profiles. + while ($row = mysql_fetch_array($result, MYSQL_NUM)) { + $userIds[] = $row[0]; } - fwrite($descriptor, "
\n"); + mysql_free_result($result); - // Previous and Next links + if (count($userIds) > 0) { + // Randomize the ordering of users. + shuffle($userIds); + } - write_page_links("user_gallery", $page, $numPages, $descriptor); + $numPages = ceil(count($userIds)/($width * $height)); - page_tail($descriptor); + // Make sure that a page is generated even when no profiles with pictures + // exist in order to avoid 404 errors from the profile_menu page. - fclose($descriptor); + if ($numPages == 0) { + $numPages = 1; + } - } - //echo "

Go to the first generated page."; + //echo "Generating $numPages pages.
"; + + $count = 0; + + for ($page = 1; $page <= $numPages; $page++) { + $file = "../html_user/" . PROFILE_PATH . "user_gallery_" . $page . ".html"; + $descriptor = fopen($file, "w"); + + page_head("User Picture Gallery: Page $page of $numPages", null, $descriptor); + + fwrite($descriptor, + "

User Profile Pictures

Last updated " + . pretty_time_str(time()) + . "\n

Browse the user profiles by picture. + Only user profiles with pictures are listed here." + ); + + fwrite($descriptor, "\n"); + + for ($row = 0; $row < $height; $row++) { + fwrite($descriptor, ""); + for ($col = 0; $col < $width; $col++) { + if ($count < $numIds) { + fwrite($descriptor, + "" + ); + $count++; + } + } + fwrite($descriptor, "\n"); + if ($count == $numIds) { + break; + } + } + + fwrite($descriptor, "
\n"); + + // Previous and Next links + + write_page_links("user_gallery", $page, $numPages, $descriptor); + + page_tail($descriptor); + + fclose($descriptor); + + } + + //echo "

Go to the first generated page."; } // Creates pages grouping user profiles by country. Filenames are of the @@ -99,51 +112,55 @@ function build_picture_pages($width, $height) { // each country. function build_country_pages() { + $query = "SELECT * FROM profile"; + $result = mysql_query($query); + $numIds = 0; - $query = "SELECT * FROM profile"; - $result = mysql_query($query); - $numIds = 0; + // Build a multi-dimensional array of countries, + // each element of which contains an array + // of the userids who belong to those countries. + // Format: array[country][index] = userid. - // Build a multi-dimensional array of countries, each element of which contains an array - // of the userids who belong to those countries. Format: array[country][index] = userid. + while ($profile = mysql_fetch_object($result)) { + $query2 = "SELECT * FROM user WHERE id=$profile->userid"; + $result2 = mysql_query($query2); + $row2 = mysql_fetch_object($result2); - while ($row = mysql_fetch_assoc($result)) { - $query2 = "SELECT * FROM user WHERE id = " . $row['userid']; - $result2 = mysql_query($query2); - $row2 = mysql_fetch_assoc($result2); - - if ($row2['country']) { - $countryMembers[$row2['country']][] = $row2['id']; - $numIds++; - } else { - $countryMembers['Other'][] = $row2['id']; + if ($row2->country) { + $countryMembers[$row2->country][] = $row2->id; + $numIds++; + } else { + $countryMembers['Other'][] = $row2->id; + } } - } - mysql_free_result($result); - mysql_free_result($result2); + mysql_free_result($result); + mysql_free_result($result2); - //echo "$numIds users have profiles AND non-null country entries.
"; + //echo "$numIds users have profiles AND non-null country entries.
"; - $countries = array_keys($countryMembers); - sort($countries); + $countries = array_keys($countryMembers); + sort($countries); - // Build the pages. - // TODO: Define a constant for the desired number of rows per page. + // Build the pages. + // TODO: Define a constant for the desired number of rows per page. - foreach ($countries as $country) { - $baseFileName = "profile_country_" . get_legal_filename($country); - $filePath = "../html_user/" . PROFILE_PATH; - build_profile_pages($countryMembers[$country], "User Profiles from $country", $country, 5, 2, $filePath, $baseFileName, "../html_user/"); + foreach ($countries as $country) { + $baseFileName = "profile_country_" . get_legal_filename($country); + $filePath = "../html_user/" . PROFILE_PATH; + build_profile_pages( + $countryMembers[$country], + "User Profiles from $country", $country, 5, 2, + $filePath, $baseFileName, "../html_user/" + ); + } - } + // Build the summary page linking to the individual country pages. - // Build the summary page linking to the individual country pages. + build_country_summary_page($countryMembers); - build_country_summary_page($countryMembers); - - //echo "
View Summary Page"; - //echo "

Done"; + //echo "
View Summary Page"; + //echo "

Done"; } @@ -179,9 +196,19 @@ function build_alpha_pages() { // NOTE: Array indexing is case sensitive. $filePath = "../html_user/" . PROFILE_PATH; if (in_array($letter, $alphabet)) { - build_profile_pages($members[$letter], "User Profiles - Names beginning with $letter", "Names beginning with $letter", 5, 2, $filePath, "profile_$letter"); + build_profile_pages( + $members[$letter], + "User Profiles - Names beginning with $letter", + "Names beginning with $letter", 5, 2, $filePath, + "profile_$letter" + ); } else { - build_profile_pages($members[$letter], "User Profiles - Names beginning with other characters", "Names beginning with other characters", 5, 2, $filePath, "profile_other"); + build_profile_pages( + $members[$letter], + "User Profiles - Names beginning with other characters", + "Names beginning with other characters", 5, 2, $filePath, + "profile_other" + ); } } @@ -222,28 +249,31 @@ function build_profile_pages($members, $pageHead, $pageTitle, $rowsPerPage, $col } function build_country_summary_page($countryMembers) { - $countries = array_keys($countryMembers); + $countries = array_keys($countryMembers); - $filename = "../html_user/" . PROFILE_PATH . "profile_country.html"; - $descriptor = fopen($filename, "w"); + $filename = "../html_user/" . PROFILE_PATH . "profile_country.html"; + $descriptor = fopen($filename, "w"); - page_head("User Profiles by Country", null, $descriptor); - fwrite($descriptor, "

User Profiles by Country

Last updated " . pretty_time_str(time()) . "

"); + page_head("User Profiles by Country", null, $descriptor); + fwrite($descriptor, "

User Profiles by Country

Last updated " . pretty_time_str(time()) . "

"); - fwrite($descriptor, "\n"); - fwrite($descriptor, "\n"); + fwrite($descriptor, "
CountryProfiles
\n"); + fwrite($descriptor, "\n"); - foreach ($countries as $country) { - $numMembers = count($countryMembers[$country]); - $name = get_legal_filename($country); + foreach ($countries as $country) { + $numMembers = count($countryMembers[$country]); + $name = get_legal_filename($country); - fwrite($descriptor, "\n\n"); - } + fwrite($descriptor, + "\n\n" + ); + } - fwrite($descriptor, "
CountryProfiles
$country$numMembers
$country$numMembers
"); - page_tail($descriptor); + fwrite($descriptor, ""); + page_tail($descriptor); - fclose($descriptor); + fclose($descriptor); } function build_alpha_summary_page($characters) { @@ -268,16 +298,34 @@ function build_alpha_summary_page($characters) { fclose($descriptor); } +function generate_uod_page($profile, $user) { + $filename = "../html_user/uotd.html"; + $descriptor = fopen($filename, "w"); + if ($profile->has_picture) { + fwrite($descriptor, + "id>" + ); + } + $x = user_links($user); + fwrite($descriptor, "The " . PROJECT . " User of the Day is $x"); + fclose($descriptor); +} + +// see if it's time to pick a new UOD. +// Either way, generate the UOD page +// function build_uotd_page() { // Check if the current UOTD has had their 24 hours of fame - if so, pick a new one. $result = mysql_query("SELECT * FROM profile ORDER BY uotd_time DESC LIMIT 1"); if (mysql_num_rows($result) > 0) { - $current_uotd = mysql_fetch_assoc($result); - $assigned = getdate($current_uotd['uotd_time']); + $current_uotd = mysql_fetch_object($result); + $assigned = getdate($current_uotd->uotd_time); $now = getdate(time()); if ($assigned['mday'] == $now['mday']) { + $user = lookup_user_id($current_uotd->userid); + generate_uod_page($current_uotd, $user); exit(); } } @@ -298,25 +346,18 @@ function build_uotd_page() { // No valid users of the day - do something. exit(); } - $profile = mysql_fetch_assoc($result); + $profile = mysql_fetch_object($result); + $user = lookup_user_id($profile->userid); + generate_uod_page($profile); - $sql = "SELECT * FROM user where id = " . $profile['userid']; - $result2 = mysql_query($sql); - $user = mysql_fetch_assoc($result2); - - $filename = "../html_user/uotd.html"; - $descriptor = fopen($filename, "w"); - - if ($profile['has_picture']) { - fwrite($descriptor, ""); - } - fwrite($descriptor, "The " . PROJECT . " User of the Day is " . $user['name'] . "!"); - fclose($descriptor); - - $sql = "UPDATE profile SET uotd_time = " . time() . " WHERE userid = " . $user['id']; + $sql = "UPDATE profile SET uotd_time = " . time() . " WHERE userid=$user->id"; mysql_query($sql); - mail($user['email_addr'], "You're the " . PROJECT . " user of the day!", "Congratulations!\n\nYou've been chosen as the " . PROJECT . " user of the day! Your profile will be featured on the " . PROJECT . " website for the next 24 hours. Thanks again for supporting us- it's members like you that make distributed computing projects like ours such a success.\n\nBest regards and much thanks,\n\nThe " . PROJECT . " team."); + mail($user->email_addr, + "You're the " . PROJECT . " user of the day!", + "Congratulations!\n\nYou've been chosen as the " + . PROJECT . " user of the day! Your profile will be featured on the " . PROJECT . " website for the next 24 hours. Thanks again for supporting us- it's members like you that make distributed computing projects like ours such a success.\n\nBest regards and much thanks,\n\nThe " . PROJECT . " team." + ); } ?> diff --git a/html/ops/update_forum_activities.php b/html/ops/update_forum_activities.php index c95210ab83..67524d043c 100755 --- a/html/ops/update_forum_activities.php +++ b/html/ops/update_forum_activities.php @@ -1,53 +1,41 @@ #!/usr/local/bin/php 0) { - $points = $points * ($dayDiff * SCALAR); - } - // Other forum activity is scaled exponentially based on the recency of the posts. +while ($thread = mysql_fetch_object($result)) { + $forum = getForum($thread->forum); + $category = getCategory($forum->category); + if ($category->is_helpdesk) { + $diff = ($now - $thread->create_time)/86400; + $activity = ($thread->sufferers+1)/$diff; + echo "help $diff $activity\n"; } else { - $sql = "SELECT * FROM post WHERE thread = " . $thread['id']; + $sql = "select * from post where thread=$thread->id"; $result2 = mysql_query($sql); - $points = 0; + $activity = 0; - while ($post = mysql_fetch_assoc($result2)) { - $timeDiff = $currentTime - $post['timestamp']; - $dayDiff = floor($timeDiff / 86400); - - $points += (MAX_REWARD / pow(2, $dayDiff)); + while ($post = mysql_fetch_object($result2)) { + $diff = $now - $post->timestamp; + $diff /= 7*86400; + $activity += pow(2, -$diff); } + echo "forum $activity\n"; } - $sql = "UPDATE thread SET activity = " . ceil($points) . " WHERE id = " . $thread['id']; + $sql = "update thread set activity=$activity where id=$thread->id"; mysql_query($sql); } -?> \ No newline at end of file +?> diff --git a/html/user/profile_menu.php b/html/user/profile_menu.php index f9d0a3c89e..6ad55e5a62 100644 --- a/html/user/profile_menu.php +++ b/html/user/profile_menu.php @@ -17,9 +17,14 @@ page_head("Profile Zone"); start_table_noborder(); rowify(" -User profiles provide a way for individuals to share backgrounds and opinions with the " . PROJECT . " community. Explore the diversity of your fellow searchers, and contribute your own views for others to enjoy. -

-If you haven't already, you can create your own user profile for others to see! + User profiles provide a way for individuals to share backgrounds + and opinions with the " . PROJECT . " community. + Explore the diversity of your fellow searchers, + and contribute your own views for others to enjoy. +

+ If you haven't already, you can + create your own user profile + for others to see! "); rowify("
"); @@ -33,97 +38,103 @@ echo ""; rowify("
"); row1("User Profile Explorer"); echo " -