user_info.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. <?php
  2. $username = $_GET['username'];
  3. requireLib('flot');
  4. $REQUIRE_LIB['mathjax'] = '';
  5. $REQUIRE_LIB['hljs'] = '';
  6. ?>
  7. <?php if (validateUsername($username) && ($user = queryUser($username))): ?>
  8. <?php echoUOJPageHeader($user['username'] . ' - ' . UOJLocale::get('user profile')) ?>
  9. <?php
  10. $esc_email = HTML::escape($user['email']);
  11. $esc_qq = HTML::escape($user['qq'] != 0 ? $user['qq'] : 'Unfilled');
  12. $esc_sex = HTML::escape($user['sex']);
  13. $col_sex="color:blue";
  14. if ($esc_sex == "M") {
  15. $esc_sex="♂";
  16. $col_sex="color:blue";
  17. } elseif ($esc_sex == "F") {
  18. $esc_sex="♀";
  19. $col_sex="color:red";
  20. } else {
  21. $esc_sex="";
  22. $col_sex="color:black";
  23. }
  24. $esc_motto = HTML::escape($user['motto']);
  25. $extgroups = $user['extgroups'];
  26. ?>
  27. <div class="card border-info">
  28. <h5 class="card-header bg-info"><?= UOJLocale::get('user profile') ?></h5>
  29. <div class="card-body">
  30. <div class="row mb-4">
  31. <div class="col-md-4 order-md-9">
  32. <img class="media-object img-thumbnail d-block mx-auto" alt="<?= $user['username'] ?> Avatar" height="250" width="250" src="<?= HTML::avatar_addr($user, 256) ?>" />
  33. </div>
  34. <div class="col-md-8 order-md-1">
  35. <h2><span class="uoj-honor" data-rating="<?= $user['rating'] ?>" data-certs="<?= $user['certs'] ?>"><?= $user['username'] ?></span> <span><strong style="<?= $col_sex ?>"><?= $esc_sex ?></strong></span></h2>
  36. <div class="list-group">
  37. <div class="list-group-item">
  38. <h4 class="list-group-item-heading"><?= UOJLocale::get('rating') ?></h4>
  39. <p class="list-group-item-text"><strong style="color:red"><?= $user['rating'] ?> (±<?= 2 * round($user['rating_rd']) ?>), vol <?= round($user['rating_vol'] * 100) / 100.0 ?></strong></p>
  40. </div>
  41. <div class="list-group-item">
  42. <h4 class="list-group-item-heading"><?= UOJLocale::get('email') ?></h4>
  43. <p class="list-group-item-text"><?= $esc_email ?></p>
  44. </div>
  45. <div class="list-group-item">
  46. <h4 class="list-group-item-heading"><?= UOJLocale::get('QQ') ?></h4>
  47. <p class="list-group-item-text"><?= $esc_qq ?></p>
  48. </div>
  49. <div class="list-group-item">
  50. <h4 class="list-group-item-heading"><?= UOJLocale::get('motto') ?></h4>
  51. <p class="list-group-item-text"><?= $esc_motto ?></p>
  52. </div>
  53. <div class="list-group-item">
  54. <h4 class="list-group-item-heading">用户组信息</h4>
  55. <p class="list-group-item-text"><?= $extgroups ?></p>
  56. </div>
  57. <?php if (isSuperUser($myUser)): ?>
  58. <div class="list-group-item">
  59. <h4 class="list-group-item-heading">register time</h4>
  60. <p class="list-group-item-text"><?= $user['register_time'] ?></p>
  61. </div>
  62. <div class="list-group-item">
  63. <h4 class="list-group-item-heading">remote_addr</h4>
  64. <p class="list-group-item-text"><?= $user['remote_addr'] ?></p>
  65. </div>
  66. <div class="list-group-item">
  67. <h4 class="list-group-item-heading">http_x_forwarded_for</h4>
  68. <p class="list-group-item-text"><?= $user['http_x_forwarded_for'] ?></p>
  69. </div>
  70. <?php endif ?>
  71. </div>
  72. </div>
  73. </div>
  74. <?php if (Auth::check()): ?>
  75. <?php if (Auth::id() != $user['username']): ?>
  76. <a type="button" class="btn btn-info btn-sm" href="/user/msg?enter=<?= $user['username'] ?>"><span class="glyphicon glyphicon-envelope"></span> <?= UOJLocale::get('send private message') ?></a>
  77. <?php else: ?>
  78. <a type="button" class="btn btn-info btn-sm" href="/user/modify-profile"><span class="glyphicon glyphicon-pencil"></span> <?= UOJLocale::get('modify my profile') ?></a>
  79. <?php endif ?>
  80. <?php endif ?>
  81. <a type="button" class="btn btn-success btn-sm" href="<?= HTML::blog_url($user['username'], '/') ?>"><span class="glyphicon glyphicon-arrow-right"></span> <?= UOJLocale::get('visit his blog', $username) ?></a>
  82. <div class="top-buffer-lg"></div>
  83. <div class="list-group">
  84. <?php
  85. $blogid = $user['aboutme_blogid'];
  86. if ($blogid) {
  87. echo '<div class="list-group-item">';
  88. echoBlog(queryBlog($blogid), array('show_content_only' => true, 'outside_blog_domain' => true));
  89. echo '</div>';
  90. }
  91. ?>
  92. <div class="list-group-item">
  93. <h4 class="list-group-item-heading"><?= UOJLocale::get('rating changes') ?></h4>
  94. <div class="list-group-item-text" id="rating-plot" style="height:500px;"></div>
  95. </div>
  96. <div class="list-group-item">
  97. <h4 class="list-group-item-heading">Rating 分布</h4>
  98. <div class="list-group-item-text" id="rating-dist-plot" style="height:500px;"></div>
  99. </div>
  100. <div class="list-group-item">
  101. <?php
  102. $ac_problems = DB::selectAll("select problem_id from best_ac_submissions where submitter = '{$user['username']}'");
  103. ?>
  104. <h4 class="list-group-item-heading"><?= UOJLocale::get('accepted problems').':'.UOJLocale::get('n problems in total', count($ac_problems))?> </h4>
  105. <p class="list-group-item-text">
  106. <?php
  107. foreach ($ac_problems as $problem) {
  108. echo '<a href="/problem/', $problem['problem_id'], '" style="display:inline-block; width:4em;">', $problem['problem_id'], '</a>';
  109. }
  110. if (empty($ac_problems)) {
  111. echo UOJLocale::get('none');
  112. }
  113. ?>
  114. </p>
  115. </div>
  116. </div>
  117. </div>
  118. </div>
  119. <script type="text/javascript">
  120. var rating_data = [[
  121. <?php
  122. $user_rating_min = $user_rating_max = 1500;
  123. $result = DB::query("select contest_id, `rank`, user_rating from contests_registrants join contests on id = contest_id where username = '{$user['username']}' and has_participated = 1 order by contests.start_time");
  124. $is_first_row = true;
  125. $last_rating = 1500;
  126. while ($row = DB::fetch($result)) {
  127. $contest = queryContest($row['contest_id']);
  128. $rating_delta = $row['user_rating'] - $last_rating;
  129. if (!$is_first_row) {
  130. echo "[$last_contest_time, {$row['user_rating']}, $last_contest_id, $last_contest_name, $last_rank, $rating_delta],";
  131. } else {
  132. $is_first_row = false;
  133. }
  134. $contest_start_time = new DateTime($contest['start_time']);
  135. $last_contest_time = ($contest_start_time->getTimestamp() + $contest_start_time->getOffset()) * 1000;
  136. $last_contest_name = json_encode($contest['name']);
  137. $last_contest_id = $contest['id'];
  138. $last_rank = $row['rank'];
  139. $last_rating = $row['user_rating'];
  140. if ($row['user_rating'] < $user_rating_min) {
  141. $user_rating_min = $row['user_rating'];
  142. }
  143. if ($row['user_rating'] > $user_rating_max) {
  144. $user_rating_max = $row['user_rating'];
  145. }
  146. }
  147. if ($is_first_row) {
  148. $time_now_stamp = (UOJTime::$time_now->getTimestamp() + UOJTime::$time_now->getOffset()) * 1000;
  149. echo "[{$time_now_stamp}, {$user['rating']}, 0]";
  150. } else {
  151. $rating_delta = $user['rating'] - $last_rating;
  152. echo "[$last_contest_time, {$user['rating']}, $last_contest_id, $last_contest_name, $last_rank, $rating_delta]";
  153. }
  154. if ($user['rating'] < $user_rating_min) {
  155. $user_rating_min = $user['rating'];
  156. }
  157. if ($user['rating'] > $user_rating_max) {
  158. $user_rating_max = $user['rating'];
  159. }
  160. $user_rating_min -= 400;
  161. $user_rating_max += 400;
  162. ?>
  163. ]];
  164. var rating_plot = $.plot($("#rating-plot"), [{
  165. color: "#3850eb",
  166. label: "<?= $user['username'] ?>",
  167. data: rating_data[0]
  168. }], {
  169. series: {
  170. lines: {
  171. show: true
  172. },
  173. points: {
  174. show: true
  175. }
  176. },
  177. xaxis: {
  178. mode: "time"
  179. },
  180. yaxis: {
  181. min: <?= $user_rating_min ?>,
  182. max: <?= $user_rating_max ?>
  183. },
  184. legend: {
  185. labelFormatter: function(username) {
  186. return getUserLink(username, <?= $user['rating'] ?>, false);
  187. }
  188. },
  189. grid: {
  190. clickable: true,
  191. hoverable: true
  192. },
  193. hooks: {
  194. drawBackground: [
  195. function(plot, ctx) {
  196. var plotOffset = plot.getPlotOffset();
  197. for (var y = 0; y < plot.height(); y++) {
  198. var rating = <?= $user_rating_max ?> - <?= $user_rating_max - $user_rating_min ?> * y / plot.height();
  199. ctx.fillStyle = getColOfRating(rating);
  200. ctx.fillRect(plotOffset.left, plotOffset.top + y, plot.width(), Math.min(5, plot.height() - y));
  201. }
  202. }
  203. ]
  204. }
  205. });
  206. function showTooltip(x, y, contents) {
  207. $('<div id="rating-tooltip">' + contents + '</div>').css({
  208. position: 'absolute',
  209. display: 'none',
  210. top: y - 20,
  211. left: x + 10,
  212. border: '1px solid #fdd',
  213. padding: '2px',
  214. 'font-size' : '11px',
  215. 'background-color': '#fee',
  216. opacity: 0.80
  217. }).appendTo("body").fadeIn(200);
  218. }
  219. var prev = -1;
  220. function onHoverRating(event, pos, item) {
  221. if (prev != item.dataIndex) {
  222. $("#rating-tooltip").remove();
  223. var params = rating_data[item.seriesIndex][item.dataIndex];
  224. var total = params[1];
  225. var contestId = params[2];
  226. if (contestId != 0) {
  227. var change = params[5] > 0 ? "+" + params[5] : params[5];
  228. var contestName = params[3];
  229. var rank = params[4];
  230. var html = "= " + total + " (" + change + "), <br/>"
  231. + "Rank: " + rank + "<br/>"
  232. + '<a href="' + '/contest/' + contestId + '">' + contestName + '</a>';
  233. } else {
  234. var html = "= " + total + "<br/>"
  235. + "Unrated";
  236. }
  237. showTooltip(item.pageX, item.pageY, html);
  238. prev = item.dataIndex;
  239. }
  240. }
  241. $("#rating-plot").bind("plothover", function (event, pos, item) {
  242. if (item) {
  243. onHoverRating(event, pos, item);
  244. }
  245. });
  246. $("#rating-plot").bind("plotclick", function (event, pos, item) {
  247. if (item && prev == -1) {
  248. onHoverRating(event, pos, item);
  249. } else {
  250. $("#rating-tooltip").fadeOut(200);
  251. prev = -1;
  252. }
  253. });
  254. (() => {
  255. var E = <?php echo $user['rating']; ?>, sigma = <?php echo $user['rating_rd']; ?>;
  256. var data = [], step = 0.1;
  257. for (var x = E - 6 * sigma; x <= E + 6 * sigma; x += step) {
  258. var e = -Math.pow(x - E, 2) / (2 * Math.pow(sigma, 2));
  259. var pdf = (1 / (sigma * Math.sqrt(2 * Math.PI))) * Math.exp(e);
  260. data.push([x, pdf]);
  261. }
  262. var realratings = [
  263. <?php
  264. $result = DB::query("select contest_id, user_rating from contests_registrants where username = '{$user['username']}' and has_participated = 1");
  265. foreach ($result as $r) echo "{$r['user_rating']}, ";
  266. echo '0';
  267. ?>
  268. ];
  269. console.log(realratings);
  270. var realdata = [];
  271. realratings.forEach((x) => {
  272. if (x >= E - 6 * sigma && x <= E + 6 * sigma) {
  273. var e = -Math.pow(x - E, 2) / (2 * Math.pow(sigma, 2));
  274. var pdf = (1 / sigma / Math.sqrt(2 * Math.PI)) * Math.exp(e);
  275. realdata.push([x, pdf]);
  276. }
  277. });
  278. console.log(realdata);
  279. $.plot('#rating-dist-plot', [{
  280. data: data,
  281. color: '#FF0000',
  282. lines: { show: true, lineWidth: 2 },
  283. points: { show: false }
  284. }, {
  285. data: realdata,
  286. color: '#0000FF',
  287. lines: { show: false },
  288. points: {
  289. show: true,
  290. radius: 3,
  291. fillColor: '#FFFFFF',
  292. symbol: 'circle'
  293. }
  294. }], {
  295. grid: { hoverable: true, borderWidth: 1 },
  296. legend: { show: true, position: 'ne' }
  297. });
  298. }) ();
  299. </script>
  300. <?php else: ?>
  301. <?php echoUOJPageHeader('不存在该用户' . ' - 用户信息') ?>
  302. <div class="card border-danger">
  303. <div class="card-header bg-danger">用户信息</div>
  304. <div class="card-body">
  305. <h4>不存在该用户</h4>
  306. </div>
  307. </div>
  308. <?php endif ?>
  309. <?php echoUOJPageFooter() ?>