.
require_once("../inc/util.inc");
require_once("../inc/boinc_db.inc");
require_once("../inc/forum_db.inc");
require_once("../inc/forum.inc");
require_once("../inc/sanitize_html.inc");
require_once("../inc/countries.inc");
require_once("../inc/credit.inc");
require_once("../inc/team_types.inc");
require_once("../inc/time.inc");
require_once("../inc/stats_sites.inc");
function team_search_form($params) {
if (!$params) {
$params = new StdClass;
$params->keywords = "";
$params->country = "";
$params->type = "";
$params->active = false;
}
echo '
';
}
function foundership_transfer_link($user, $team) {
$now = time();
if ($team->ping_user == $user->id) {
if (transfer_ok($team, $now)) {
return tra('Requested by you, and founder response deadline has passed.').'
'.tra('Complete foundership transfer').'.
';
} else {
$deadline = date_str(transfer_ok_time($team));
return ''.tra('Requested by you').'; '.tra('founder response deadline is %1', $deadline);
}
}
if (new_transfer_request_ok($team, $now)) {
if ($team->userid == $user->id) {
return tra('None');
} else {
return ''.tra('Initiate request').'';
}
}
return ''.tra('Deferred').'';
}
// $team is the team record with a bunch of additional data
// (see team_display.php)
// $user is viewer (not necessarily team founder) or null
//
function display_team_page($team, $user) {
global $team_name_sites;
page_head("$team->name");
echo sanitize_html($team->name_html);
echo "";
start_table();
row1(tra('Team info'));
if (strlen($team->description)) {
row2(tra('Description'), sanitize_html($team->description));
}
row2("Created", date_str($team->create_time));
if (defined("SHOW_NONVALIDATED_TEAMS")) {
$founder = $team->founder;
row2("Founder email validated", $founder->email_validated?"Yes":"No (team will not be exported)");
}
if (strlen($team->url)) {;
if (strstr($team->url, "http://")) {
$x = $team->url;
} else {
$x = "http://$team->url";
}
row2(tra('Web site'), "$x");
}
if (!NO_STATS) {
row2(tra('Total credit'), format_credit_large($team->total_credit));
row2(tra('Recent average credit'), format_credit_large($team->expavg_credit));
if (function_exists('project_team_credit')) {
project_team_credit($team);
}
}
show_badges_row(false, $team);
if (!NO_STATS) {
$x = "";
shuffle($team_name_sites);
foreach ($team_name_sites as $t) {
$url = $t[0];
$site_name = $t[1];
$encoding = $t[2];
if ($encoding == "hashlc") {
$key = md5(strtolower($team->name));
} else if ($encoding == 'hash') {
$key = md5($team->name);
} else {
$key = urlencode($team->name);
}
$x .= "$site_name
\n";
}
row2(tra('Cross-project stats'), $x);
}
row2(tra('Country'), $team->country);
row2(tra('Type'), team_type_name($team->type));
if ($team->forum && is_forum_visible_to_user($team->forum, $user)) {
$f = $team->forum;
row2(''.tra('Message board').'',
tra('Threads').': '.$f->threads.'
'.tra('Posts').': '.$f->posts.'
'.tra('Last post').': '.time_diff_str($f->timestamp, time())
);
}
if ($user) {
if ($user->teamid != $team->id) {
if ($team->joinable) {
$tokens = url_tokens($user->authenticator);
row2("",
''.tra('Join this team').'
'.tra('Note: if \'OK to email\' is set in your project preferences, joining a team gives its founder access to your email address.').'
'
);
} else {
row2(tra("Not accepting new members"), "");
}
}
if (($user->teamid == $team->id)) {
if (($user->id == $team->userid)) {
if ($team->ping_user) {
$deadline = date_str(transfer_ok_time($team));
row2(tra('Foundership change requested'),
''.tra('Respond by %1', $deadline).''
);
}
} else {
row2(tra('Team foundership change'), foundership_transfer_link($user, $team));
}
}
}
row1(tra('Members'));
row2(tra('Founder'),
$team->founder?user_links($team->founder, BADGE_HEIGHT_MEDIUM):"---"
);
if (count($team->admins)) {
$first = true;
$x = "";
foreach ($team->admins as $a) {
if ($first) {
$first = false;
} else {
$x .= " · ";
}
$x .= user_links($a, BADGE_HEIGHT_MEDIUM);
}
row2(tra('Admins'), $x);
}
$x = "0";
if (count($team->new_members)) {
$first = true;
$x = "";
foreach ($team->new_members as $a) {
if ($first) {
$first = false;
} else {
$x .= " · ";
}
$x .= user_links($a, BADGE_HEIGHT_MEDIUM);
}
}
row2(tra('New members in last day'), $x);
row2(tra('Total members'), "$team->nusers (id&offset=0&sort_by=expavg_credit>".tra('view').")");
if (!NO_STATS) {
row2(tra('Active members'), "$team->nusers_active (id&offset=0&sort_by=expavg_credit>".tra('view').")");
row2(tra('Members with credit'), "$team->nusers_worked (id&offset=0&sort_by=total_credit>".tra('view').")");
}
end_table();
}
function display_team_members($team, $offset, $sort_by) {
$n = 20;
$admins = BoincTeamAdmin::enum("teamid=$team->id");
// there aren't indices to support sorting by credit.
// set the following variable to disable sorted output.
// (though since caching is generally used this shouldn't be needed)
//
$nosort = false;
if ($sort_by == "total_credit") {
$sort_clause = "total_credit desc";
} else {
$sort_clause = "expavg_credit desc";
}
start_table();
$x = array();
$a = array();
$x[] = tra('Name');
$a[] = "";
if (!NO_STATS) {
if ($nosort) {
$x[] = tra('Total credit');
$x[] = tra('Recent average credit');
} else {
if ($sort_by == "total_credit") {
$x[] = tra('Total credit');
} else {
$x[] = "id&sort_by=total_credit&offset=$offset>".tra('Total credit')."";
}
if ($sort_by == "expavg_credit") {
$x[] = tra('Recent average credit');
} else {
$x[] = "id&sort_by=expavg_credit&offset=$offset>".tra('Recent average credit').'';
}
}
$a[] = ALIGN_RIGHT;
$a[] = ALIGN_RIGHT;
}
$x[] = tra('Country');
$a[] = "";
row_heading_array($x, $a);
$cache_args = "teamid=".$team->id."&mosort=".$nosort."&order=".$sort_clause."&limit=".$offset."_".$n;
$users = unserialize(get_cached_data(TEAM_PAGE_TTL, $cache_args));
if (!$users) {
if ($nosort) {
$users = BoincUser::enum("teamid=$team->id limit $offset,$n");
} else {
$users = BoincUser::enum("teamid=$team->id order by $sort_clause limit $offset,$n");
}
set_cached_data(TEAM_PAGE_TTL, serialize($users), $cache_args);
}
$j = $offset + 1;
foreach ($users as $user) {
$user_total_credit = format_credit_large($user->total_credit);
$user_expavg_credit = format_credit($user->expavg_credit);
$x = user_links($user, BADGE_HEIGHT_MEDIUM);
if ($user->id == $team->userid) {
$x .= ' ['.tra('Founder').']';
} else if (is_team_admin_aux($user, $admins)) {
$x .= ' ['.tra('Admin').']';
}
echo "
$j) $x
| ";
if (!NO_STATS) {
echo "
$user_total_credit |
$user_expavg_credit |
";
}
echo "
$user->country |
";
$j++;
}
echo "";
if ($offset > 0) {
$new_offset = $offset - $n;
echo "id&sort_by=$sort_by&offset=$new_offset>".tra('Previous %1', $n)." · ";
}
if ($j == $offset + $n + 1) {
$new_offset = $offset + $n;
echo "id&sort_by=$sort_by&offset=$new_offset>".tra('Next %1', $n)."";
}
}
// check that the team exists
//
function require_team($team) {
if (!$team) {
error_page(tra('No such team.'));
}
}
function is_team_founder($user, $team) {
return $user->id == $team->userid;
}
// check that the user is founder of the team
//
function require_founder_login($user, $team) {
require_team($team);
if ($user->id != $team->userid) {
error_page(tra('This operation requires foundership.'));
}
}
function is_team_admin($user, $team) {
if (!$user) return false;
if ($user->id == $team->userid) return true;
$admin = BoincTeamAdmin::lookup($team->id, $user->id);
if ($admin) return true;
return false;
}
// use this when you're displaying a long list of users
// and don't want to do a lookup for each one
//
function is_team_admin_aux($user, $admins) {
foreach ($admins as $a) {
if ($a->userid == $user->id) return true;
}
return false;
}
function require_admin($user, $team) {
if (!is_team_admin($user, $team)) {
error_page(tra('This operation requires team admin privileges'));
}
}
// return list of ID of user who joined team in last day
//
function new_member_list($teamid) {
$new_members = array();
$yesterday = time() - 86400;
$deltas = BoincTeamDelta::enum("teamid=$teamid and timestamp>$yesterday and joining=1");
foreach ($deltas as $delta) {
$u = BoincUser::lookup_id($delta->userid);
if ($u->teamid == $teamid) {
$new_members[] = $u; // they might have later quit
}
}
return array_unique($new_members);
}
function admin_list($teamid) {
$u = array();
$admins = BoincTeamAdmin::enum("teamid=$teamid");
foreach ($admins as $admin) {
$user = BoincUser::lookup_id($admin->userid);
$u[] = $user;
}
return $u;
}
function team_table_start($sort_by, $type_url) {
$x = array();
$x[] = tra('Rank');
$x[] = tra('Name');
$x[] = tra('Members');
$a = array("", "", ALIGN_RIGHT);
if (!NO_STATS) {
if ($sort_by == "total_credit") {
$x[] = "".tra('Recent average credit')."";
$x[] = tra('Total credit');
} else {
$x[] = tra('Recent average credit');
$x[] = "".tra('Total credit')."";
}
$a[] = ALIGN_RIGHT;
$a[] = ALIGN_RIGHT;
}
$x[] = tra('Country');
$x[] = tra("Type");
$a[] = "";
$a[] = "";
row_heading_array($x, $a);
}
function team_links($team) {
$b = badges_string(false, $team, BADGE_HEIGHT_MEDIUM);
return "id>$team->name $b";
}
function show_team_row($team, $i) {
$team_expavg_credit = format_credit_large($team->expavg_credit);
$team_total_credit = format_credit_large($team->total_credit);
echo "
$i |
".team_links($team)." |
".$team->nusers." |
";
if (!NO_STATS) {
echo "
$team_expavg_credit |
$team_total_credit |
";
}
echo "
$team->country |
".team_type_name($team->type)." |
";
}
function user_join_team($team, $user) {
user_quit_team($user);
$res = $user->update("teamid=$team->id");
if ($res) {
$now = time();
BoincTeamDelta::insert("(userid, teamid, timestamp, joining, total_credit) values ($user->id, $team->id, $now, 1, $user->total_credit)");
return true;
}
return false;
}
function user_quit_team($user) {
if (!$user->teamid) return;
$user->update("teamid=0");
$team = BoincTeam::lookup_id($user->teamid);
if ($team && $team->ping_user==$user->id) {
$team->update("ping_user=-ping_user");
}
BoincTeamAdmin::delete("teamid=$user->teamid and userid=$user->id");
$now = time();
BoincTeamDelta::insert("(userid, teamid, timestamp, joining, total_credit) values ($user->id, $user->teamid, $now, 0, $user->total_credit)");
}
function user_erase_team_owner($user) {
if ($user->teamid) {
$team = BoincTeam::lookup_id($user->teamid);
if ($team && $team->userid == $user->id) {
$team->update("userid=0");
}
}
}
function user_erase_team_delta($user) {
BoincTeamDelta::delete_for_user($user->id);
}
function team_edit_form($team, $label, $url) {
global $team_types, $recaptcha_public_key;
echo "\n";
}
// decay a team's average credit
//
function team_decay_credit($team) {
$avg = $team->expavg_credit;
$avg_time = $team->expavg_time;
$now = time();
update_average($now, 0, 0, $avg, $avg_time);
$team->update("expavg_credit=$avg, expavg_time=$now");
}
// if the team hasn't received new credit for ndays,
// decay its average and return true
//
function team_inactive_ndays($team, $ndays) {
$diff = time() - $team->expavg_time;
if ($diff > $ndays*86400) {
team_decay_credit($team);
return true;
}
return false;
}
function team_count_members($teamid) {
return BoincUser::count("teamid=$teamid");
}
// These functions determine the rules for foundership transfer, namely:
// - A transfer request is allowed if either:
// - there is no active request, and it's been at least 60 days
// since the last request (this protects the founder from
// being bombarded with frequest requests)
// - there's an active request older than 90 days
// (this lets a 2nd requester eventually get a chance)
// - Suppose someone (X) requests foundership at time T.
// An email is sent to the founder (Y).
// The request is "active" (ping_user is set to X's ID)
// - If Y declines the change, an email is sent to X,
// and the request is cleared.
// - If Y accepts the change, an email is sent to X
// and the request is cleared.
// - After T + 60 days, X can become founder
// - After T + 90 days, new requests are allowed even if there's
// an active request, i.e. after the 60 days elapse X has another
// 30 days to assume foundership before someone elase can request it
//
function new_transfer_request_ok($team, $now) {
if ($team->ping_user <= 0) {
if ($team->ping_time < $now - 60 * 86400) {
return true;
}
return false;
}
if ($team->ping_time < $now - 90 * 86400) {
return true;
}
return false;
}
// the time at which we can actually change foundership
// if the founder hasn't responded
//
function transfer_ok_time($team) {
return $team->ping_time + 60*86400;
}
function transfer_ok($team, $now) {
if ($now > transfer_ok_time($team)) return true;
return false;
}
// Make a team; args are untrusted, so cleanse and validate them
//
function make_team(
$userid, $name, $url, $type, $name_html, $description, $country
) {
$name = BoincDb::escape_string(sanitize_tags($name));
if (strlen($name) == 0) return null;
$name_lc = strtolower($name);
$url = BoincDb::escape_string(sanitize_tags($url));
if (strstr($url, "http://")) {
$url = substr($url, 7);
}
$name_html = BoincDb::escape_string($name_html);
$description = BoincDb::escape_string($description);
if (!is_valid_country($country)) {
$country = tra('None');
}
$country = BoincDb::escape_string($country); // for Cote d'Ivoire
$clause = sprintf(
"(userid, create_time, name, name_lc, url, type, name_html, description, country, nusers, expavg_time) values(%d, %d, '%s', '%s', '%s', %d, '%s', '%s', '%s', %d, unix_timestamp())",
$userid,
time(),
$name,
$name_lc,
$url,
$type,
$name_html,
$description,
$country,
0
);
$id = BoincTeam::insert($clause);
if ($id) {
return BoincTeam::lookup_id($id);
} else {
return null;
}
}
$cvs_version_tracker[]="\$Id$"; //Generated automatically - do not edit
?>