diff --git a/html/ops/badge_assign_custom.php b/html/ops/badge_assign_custom.php new file mode 100755 index 0000000000..8e12a67729 --- /dev/null +++ b/html/ops/badge_assign_custom.php @@ -0,0 +1,189 @@ +#!/usr/bin/env php +. + +// Assign badges based on project total and per subproject credit. +// This code is mostly generic. +// You'll need to: +// - define your subproject in project/project.inc +// - use the option in config.xml +// - supply your own project themed badge images +// that have to follow a naming scheme (see below) +// See: http://boinc.berkeley.edu/trac/wiki/PerAppCredit + +require_once("../inc/util_ops.inc"); + +// use $sub_projects defined in project/project.inc +// (this speeds up the assignment of badges) +// "total" is a special sub project and should only be defined here +// +global $sub_projects; +$badges_sub_projects = $sub_projects; +$badges_sub_projects[] = array("name" => "project total", "short_name" => "total"); + +// thresholds for the various badges +// currently we use the same threshold for all badges (total and subproject) +// minimum total credits for each level and corresponding names +// +$badge_levels = array( + 50000000, 100000000, 250000000, 500000000, 1000000000, 10000000000, + 250000000000, 500000000000 +); +$badge_level_names = array( + "50M", "100M", "250M", "500M", "1B", "10B", "25B", "50B" +); + +// images located in html/user/img/ for each badge level +// the actual filename must have the subproject short name or "total" as prefix +// e.g.: A_bronze.png is the first level of subproject A, +// total_bronze.png is the first level of total credit (across all subprojects) +// +$badge_images = array( + "_bronze.png", "_silver.png", "_gold.png", "_amethyst.png", + "_turquoise.png", "_sapphire.png", "_ruby.png", "_emerald.png" +); + +// consistency checks +// +$num_levels = count($badge_levels); +if ($num_levels <> count($badge_level_names)) { + die("number of badge_levels is not equal to number of badge_level_names"); +} +if ($num_levels <> count($badge_images)) { + die("number of badge_levels is not equal to number of badge_images"); +} + +// get the record for a badge (either total or subproject) +// badge_name_prefix should be user or team +// sub_project is an array with name and short_name as in $sub_projects +// +function get_badges( + $badge_name_prefix, $badge_level_names, $badge_images, $sub_project +) { + $badges = array(); + for ($i=0; $i=0; $i--) { + if ($item->total_credit >= $levels[$i]) { + assign_badge($is_user, $item, $badges[$i]); + unassign_badges($is_user, $item, $badges, $i); + return; + } + } + // no level could be assigned so remove them all + // + unassign_badges($is_user, $item, $badges, -1); +} + +// decide which subproject badge to assign, if any. +// Unassign other badges. +// +function assign_sub_badge($is_user, $item, $levels, $badges, $where_clause) { + if ($is_user) { + $sub_total = BoincCreditUser::sum('total', "where userid=".$item->id." and ($where_clause)"); + } else { + $sub_total = BoincCreditTeam::sum('total', "where teamid=".$item->id." and ($where_clause)"); + } + // count from highest to lowest level, so the user get's assigned the + // highest possible level and the lower levels get removed + // + for ($i=count($levels)-1; $i>=0; $i--) { + if ($sub_total >= $levels[$i]) { + assign_badge($is_user, $item, $badges[$i]); + unassign_badges($is_user, $item, $badges, $i); + return; + } + } + // no level could be assigned so remove them all + // + unassign_badges($is_user, $item, $badges, -1); +} + + +// Scan through all the users/teams, 1000 at a time, +// and assign/unassign the badges (total and subproject) +// +function assign_all_badges( + $is_user, $badge_levels, $badge_level_names, $badge_images, + $subprojects_list +) { + $kind = $is_user?"user":"team"; + + // get badges for all subprojects including total + // + foreach ($subprojects_list as $sp) { + $badges[$sp["short_name"]] = get_badges($kind, $badge_level_names, $badge_images, $sp); + } + + $n = 0; + $maxid = $is_user?BoincUser::max("id"):BoincTeam::max("id"); + while ($n <= $maxid) { + $m = $n + 1000; + if ($is_user) { + $items = BoincUser::enum_fields("id, total_credit", "id>=$n and id<$m and total_credit>0"); + } else { + $items = BoincTeam::enum_fields("id, total_credit", "id>=$n and id<$m and total_credit>0"); + } + // for every user/team + // + foreach ($items as $item) { + // for every subproject (incl. total) + // + foreach ($subprojects_list as $sp) { + if ($sp["short_name"] == "total") { + assign_tot_badge($is_user, $item, $badge_levels, $badges["total"]); + } else { + // appids come from project/project.inc + $where_clause = "appid in (". implode(',', $sp["appids"]) .")"; + assign_sub_badge( + $is_user, $item, $badge_levels, $badges[$sp["short_name"]], + $where_clause + ); + } + } + } + $n = $m; + } +} + +// one pass through DB for users +// +assign_all_badges( + true, $badge_levels, $badge_level_names, $badge_images, + $badges_sub_projects +); + +// one pass through DB for teams +// +assign_all_badges( + false, $badge_levels, $badge_level_names, $badge_images, + $badges_sub_projects +); + +?> diff --git a/html/project.sample/project.inc b/html/project.sample/project.inc index 32429e6c7c..deacab6935 100644 --- a/html/project.sample/project.inc +++ b/html/project.sample/project.inc @@ -179,9 +179,15 @@ function show_app_credit_team($team, $app_name, $appids) { ); } +// a list of "sub-projects", used in the display of per-app credit and badges. +// A subproject is: +// - a set of 1 or more apps; an app can belong to at most 1 subproject. +// - a name, shown on the web site +// - a short name, used in badge names. Don't use "total". +// $sub_projects = array( - array("name" => "Remote Test", "appids" => array(16)), - array("name" => "Uppercase", "appids" => array(1, 25)), + array("name" => "Remote Test", "short_name" => "RT", "appids" => array(16)), + array("name" => "Uppercase", "short_name" => "UC", "appids" => array(1, 25)), ); function project_user_credit($user){