From 65b5ab5184f3f96bb37388621273eee9dd614acd Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 5 Dec 2013 10:14:26 -0800 Subject: [PATCH] server/web: preliminary support for badges - DB: add tables for badges and badge/user and badge/team associations - add script that defines 3 RAC-based badges and assigns them - add images for these badges - add admin page for creating/editing badges - show badges on user page not done: - figure out how to send badges to client - display badges somewhere in the GUIs - export badges in db_dump - enable badges by default for new projects --- db/constraints.sql | 6 ++ db/schema.sql | 34 ++++++++++++ html/inc/boinc_db.inc | 68 +++++++++++++++++++++++ html/inc/user.inc | 11 ++++ html/inc/util.inc | 2 +- html/ops/badge_admin.php | 114 ++++++++++++++++++++++++++++++++++++++ html/ops/badge_assign.php | 105 +++++++++++++++++++++++++++++++++++ html/ops/index.php | 1 + html/user/img/bronze.png | Bin 0 -> 3998 bytes html/user/img/gold.png | Bin 0 -> 23661 bytes html/user/img/silver.png | Bin 0 -> 23273 bytes html/user/show_user.php | 4 ++ 12 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 html/ops/badge_admin.php create mode 100755 html/ops/badge_assign.php create mode 100644 html/user/img/bronze.png create mode 100644 html/user/img/gold.png create mode 100644 html/user/img/silver.png diff --git a/db/constraints.sql b/db/constraints.sql index e32daffb21..537bda945e 100644 --- a/db/constraints.sql +++ b/db/constraints.sql @@ -132,3 +132,9 @@ alter table assignment alter table job_file add unique jf_md5(md5); + +alter table badge_user + add unique (user_id, badge_id); + +alter table badge_team + add unique(team_id, badge_id); diff --git a/db/schema.sql b/db/schema.sql index 063f47a9bc..b5596ac005 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -690,3 +690,37 @@ create table notify ( opaque integer not null -- some other ID, e.g. that of the thread, user or PM record ); + +create table badge ( + id serial primary key, + create_time double not null, + type tinyint not null, + -- 0=user, 1=team + name varchar(255) not null, + -- internal use (not visible to users) + title varchar(255) not null, + -- user-visible, short + description varchar(255) not null, + -- user-visible, possibly longer + image_url varchar(255) not null, + -- location of image + level varchar(255) not null, + -- project-defined + tags varchar(255) not null, + -- project-defined + sql_rule varchar(255) not null +); + +create table badge_user ( + badge_id integer not null, + user_id integer not null, + create_time double not null, + reassign_time double not null +); + +create table badge_team ( + badge_id integer not null, + team_id integer not null, + create_time double not null, + reassign_time double not null +); diff --git a/html/inc/boinc_db.inc b/html/inc/boinc_db.inc index fbf5853618..afde1d0dbd 100644 --- a/html/inc/boinc_db.inc +++ b/html/inc/boinc_db.inc @@ -501,4 +501,72 @@ function latest_avs_app($appid) { return $r; } +class BoincBadge { + static function enum($where_clause) { + $db = BoincDb::get(); + return $db->enum('badge', 'BoincBadge', $where_clause); + } + static function insert($clause) { + $db = BoincDb::get(); + $ret = $db->insert('badge', $clause); + if (!$ret) return 0; + return $db->insert_id(); + } + function update($clause) { + $db = BoincDb::get(); + return $db->update($this, 'badge', $clause); + } + static function lookup_id($id) { + $db = BoincDb::get(); + return $db->lookup_id($id, 'badge', 'BoincBadge'); + } + static function lookup($clause) { + $db = BoincDb::get(); + return $db->lookup('badge', 'BoincBadge', $clause); + } +} + +class BoincBadgeUser { + static function enum($where_clause) { + $db = BoincDb::get(); + return $db->enum('badge_user', 'BoincBadgeUser', $where_clause); + } + static function insert($clause) { + $db = BoincDb::get(); + $ret = $db->insert('badge_user', $clause); + if (!$ret) return false; + return true; + } + static function lookup($clause) { + $db = BoincDb::get(); + return $db->lookup('badge_user', 'BoincBadgeUser', $clause); + } + static function update($clause) { + $db = BoincDb::get(); + return $db->update_aux('badge_user', $clause); + } + function delete($clause) { + $db = BoincDb::get(); + $db->delete_aux('badge_user', $clause); + } +} + +class BoincBadgeTeam { + static function lookup($clause) { + $db = BoincDb::get(); + return $db->lookup('badge_team', 'BoincBadgeTeam', $clause); + } + static function insert($clause) { + $db = BoincDb::get(); + $ret = $db->insert('badge_team', $clause); + if (!$ret) return false; + return true; + } + function delete($clause) { + $db = BoincDb::get(); + $db->delete_aux('badge_team', $clause); + } +} + + ?> diff --git a/html/inc/user.inc b/html/inc/user.inc index 7245705e57..7c802f551e 100644 --- a/html/inc/user.inc +++ b/html/inc/user.inc @@ -396,6 +396,17 @@ function community_links($clo, $logged_in_user){ } } +function show_badges($user) { + $bus = BoincBadgeUser::enum("user_id=$user->id"); + if (!$bus) return; + $x = ""; + foreach ($bus as $bu) { + $badge = BoincBadge::lookup_id($bu->badge_id); + $x .= "title\" height=40 src=$badge->image_url> "; + } + row2("Badges", $x); +} + function show_profile_link($user) { if ($user->has_profile) { row2(tra("Profile"), "id\">".tra("View").""); diff --git a/html/inc/util.inc b/html/inc/util.inc index aff315d58c..aef4ca3b15 100644 --- a/html/inc/util.inc +++ b/html/inc/util.inc @@ -327,7 +327,7 @@ function table_header() { $col = func_get_arg($i); echo "".$col[0]."\n"; } else { - echo "".func_get_arg($i)."\n"; + echo "".func_get_arg($i)."\n"; } } echo "\n"; diff --git a/html/ops/badge_admin.php b/html/ops/badge_admin.php new file mode 100644 index 0000000000..0f7031f76a --- /dev/null +++ b/html/ops/badge_admin.php @@ -0,0 +1,114 @@ +. + +// web interface for administering badges + +require_once('../inc/util_ops.inc'); + +function show_form() { + start_table(); + table_header( + "ID", + "name", + "type
0=user
1=team", + "title", + "description", + "image URL", + "level", + "tags" + ); + + $badges = BoincBadge::enum(""); + foreach ($badges as $badge) { + echo "
"; + echo "id>"; + echo "$badge->id\n"; + echo "name\">\n"; + echo "type\">\n"; + echo "title\">\n"; + echo "description\">\n"; + $x = ""; + if ($badge->image_url) { + $x = " image_url\">"; + } + echo "image_url\">$x\n"; + echo "level\">\n"; + echo "tags\">\n"; + echo "\n"; + echo "
\n"; + } + + echo "
"; + echo "
\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "
\n"; + + end_table(); +} + +function add_badge() { + $name = BoincDb::escape_string(post_str("name")); + $type = post_int("type"); + $title = BoincDb::escape_string(post_str("title")); + $description = BoincDb::escape_string(post_str("description")); + $image_url = BoincDb::escape_string(post_str("image_url")); + $level = BoincDb::escape_string(post_str("level")); + $tags = BoincDb::escape_string(post_str("tags")); + $now = time(); + $id = BoincBadge::insert("(create_time, name, type, title, description, image_url, level, tags) values ($now, '$name', $type, '$title', '$description', '$image_url', '$level', '$tags')"); + if (!$id) { + admin_error_page("Insert failed"); + } +} + +function update_badge() { + $id = post_int("id"); + $badge = BoincBadge::lookup_id($id); + if (!$badge) { + admin_error_page("no such badge"); + } + $name = BoincDb::escape_string(post_str("name")); + $type = post_int("type"); + $title = BoincDb::escape_string(post_str("title")); + $description = BoincDb::escape_string(post_str("description")); + $image_url = BoincDb::escape_string(post_str("image_url")); + $level = BoincDb::escape_string(post_str("level")); + $tags = BoincDb::escape_string(post_str("tags")); + $retval = $badge->update("name='$name', type=$type, title='$title', description='$description', image_url='$image_url', level='$level', tags='$tags'"); + if (!$retval) { + admin_error_page("update failed"); + } +} + + +if (post_str('add_badge', true)) { + add_badge(); +} else if (post_str('update', true)) { + update_badge(); +} +admin_page_head("Manage badges"); +show_form(); +admin_page_tail(); +?> diff --git a/html/ops/badge_assign.php b/html/ops/badge_assign.php new file mode 100755 index 0000000000..61c913147f --- /dev/null +++ b/html/ops/badge_assign.php @@ -0,0 +1,105 @@ +#!/usr/bin/env php +. + +// Assign badges based on RAC. +// Customize this to grant other types of badges + +require_once("../inc/boinc_db.inc"); + +define("GOLD_RAC", 100000); +define("SILVER_RAC", 10000); +define("BRONZE_RAC", 1000); + +function get_badge($name, $t, $rac, $image_url) { + $b = BoincBadge::lookup("name='$name'"); + if ($b) return $b; + $now = time(); + $title = "$t badge: average credit > $rac"; + $id = BoincBadge::insert("(create_time, name, title, image_url) values ($now, '$name', '$title', 'img/$image_url')"); + $b = BoincBadge::lookup_id($id); + if ($b) return $b; + die("can't create badge $name\n"); +} + +$rac_gold = get_badge("rac_gold", "Gold", GOLD_RAC, "gold.png"); +$rac_silver = get_badge("rac_silver", "Silver", SILVER_RAC, "silver.png"); +$rac_bronze = get_badge("rac_bronze", "Bronze", BRONZE_RAC, "bronze.png"); + +function assign_badge($user, $badge) { + $now = time(); + $bbu = BoincBadgeUser::lookup("user_id=$user->id and badge_id=$badge->id"); + if ($bbu) { + echo "reassigning $badge->name to $user->id\n"; + $bbu->update("reassign_time=$now where user_id=$user->id and badge_id=$badge->id"); + } else { + echo "assigning $badge->name to $user->id\n"; + BoincBadgeUser::insert("(create_time, user_id, badge_id, reassign_time) values ($now, $user->id, $badge->id, $now)"); + } +} + +function unassign_badges($user, $badges) { + $list = null; + foreach($badges as $badge) { + echo "unassigning $badge->name to $user->id\n"; + if ($list) { + $list .= ",$badge->id"; + } else { + $list = "$badge->id"; + } + } + BoincBadgeUser::delete("user_id=$user->id and badge_id in ($list)"); +} + +function assign_rac_badge($user) { + global $rac_gold, $rac_silver, $rac_bronze; + if ($user->expavg_credit > GOLD_RAC) { + assign_badge($user, $rac_gold); + unassign_badges($user, array($rac_silver, $rac_bronze)); + } else if ($user->expavg_credit > SILVER_RAC) { + assign_badge($user, $rac_silver); + unassign_badges($user, array($rac_bronze, $rac_gold)); + } else if ($user->expavg_credit > BRONZE_RAC) { + assign_badge($user, $rac_bronze); + unassign_badges($user, array($rac_gold, $rac_silver)); + } else { + unassign_badges($user, array($rac_gold, $rac_silver, $rac_bronze)); + } +} + +function assign_badges_user($user) { + assign_rac_badge($user); + // ... assign other types of badges +} + +function assign_badges() { + $n = 0; + $maxid = BoincUser::max("id"); + while ($n <= $maxid) { + $m = $n + 1000; + $users = BoincUser::enum_fields("id, expavg_credit", "id>=$n and id<$m and total_credit>0"); + foreach ($users as $user) { + assign_badges_user($user); + } + $n = $m; + } +} + +assign_badges(); + +?> diff --git a/html/ops/index.php b/html/ops/index.php index 3d2cb93a42..c474d67e29 100644 --- a/html/ops/index.php +++ b/html/ops/index.php @@ -114,6 +114,7 @@ echo " User management