feat(web): disable register & add user manager

This commit is contained in:
Baoshuo Ren 2022-03-17 19:38:33 +08:00
parent 3964f64c14
commit a6e18b25bd
Signed by: baoshuo
GPG Key ID: 00CB9680AB29F51A
4 changed files with 389 additions and 64 deletions

View File

@ -13,6 +13,10 @@
return "无效表单";
}
if (DB::selectCount("SELECT COUNT(*) FROM user_info")) {
return "只有首位用户可以注册。";
}
$username = $_POST['username'];
$password = $_POST['password'];
$email = $_POST['email'];

View File

@ -1,4 +1,7 @@
<?php
$REQUIRE_LIB['md5'] = '';
$REQUIRE_LIB['jquery.query'] = '';
requirePHPLib('form');
requirePHPLib('judger');
@ -6,6 +9,74 @@
become403Page();
}
$register_form = new UOJForm('register');
$register_form->submit_button_config['align'] = 'compressed';
$register_form->addInput('new_username', 'text', '用户名', '',
function ($new_username) {
if (!validateUsername($new_username)) {
return '用户名不合法';
}
if (queryUser($new_username)) {
return '该用户已存在';
}
return '';
},
null
);
$register_form->addInput('new_password', 'password', '密码', '',
function ($new_password) {
return '';
},
null
);
$register_form->addInput('new_realname', 'text', '真实姓名', '',
function ($new_realname) {
return '';
},
null
);
$register_form->handle = function() {
$new_username = $_POST['new_username'];
$new_password = $_POST['new_password'];
$new_realname = $_POST['new_realname'];
$new_password = hash_hmac('md5', $new_password, getPasswordClientSalt());
$new_password = getPasswordToStore($new_password, $new_username);
$svn_pw = uojRandString(10);
DB::query("insert into user_info (username, realname, password, svn_password, register_time, usergroup) values ('$new_username', '$new_realname', '$new_password', '$svn_pw', now(), 'U')");
};
$register_form->runAtServer();
$change_password_form = new UOJForm('change_password');
$change_password_form->submit_button_config['align'] = 'compressed';
$change_password_form->addInput('p_username', 'text', '用户名', '',
function ($p_username) {
if (!validateUsername($p_username)) {
return '用户名不合法';
}
if (!queryUser($p_username)) {
return '用户不存在';
}
return '';
},
null
);
$change_password_form->addInput('p_password', 'password', '密码', '',
function ($p_password) {
return '';
},
null
);
$change_password_form->handle = function() {
$p_username = $_POST['p_username'];
$p_password = $_POST['p_password'];
$p_password = hash_hmac('md5', $p_password, getPasswordClientSalt());
$p_password = getPasswordToStore($p_password, $p_username);
DB::query("update user_info set password = '$p_password' where username = '$p_username'");
};
$change_password_form->runAtServer();
$change_realname_form = new UOJForm('change_realname');
$change_realname_form->submit_button_config['align'] = 'compressed';
$change_realname_form->addInput('r_username', 'text', '用户名', '',
@ -53,12 +124,12 @@
'normaluser' => '设为普通用户',
'superuser' => '设为超级用户'
);
$user_form->addSelect('op-type', $options, '操作类型', '');
$user_form->addSelect('op_type', $options, '操作类型', '');
$user_form->handle = function() {
global $user_form;
$username = $_POST['username'];
switch ($_POST['op-type']) {
switch ($_POST['op_type']) {
case 'banneduser':
DB::update("update user_info set usergroup = 'B' where username = '{$username}'");
break;
@ -327,27 +398,48 @@ EOD;
EOD;
};
$banlist_cols = array('username', 'usergroup');
$banlist_config = array();
$banlist_header_row = <<<EOD
$userlist_cols = array('username', 'usergroup', 'register_time');
$userlist_config = array('page_len' => 20,
'table_classes' => array('table', 'table-bordered', 'table-hover', 'table-striped'));
$userlist_header_row = <<<EOD
<tr>
<th>用户名</th>
<th style="width: 6em">用户类别</th>
<th style="width: 12em">注册时间</th>
</tr>
EOD;
$banlist_print_row = function($row) {
$cur_tab = isset($_GET['tab']) ? $_GET['tab'] : 'users';
$user_list_cond = array();
if ($cur_tab === 'users') {
if (isset($_GET['username']) && $_GET['username'] != "") {
$user_list_cond[] = "username like '%" . DB::escape($_GET['username']) . "%'";
}
if (isset($_GET['usergroup']) && $_GET['usergroup'] != "") {
$user_list_cond[] = "usergroup = '" . DB::escape($_GET['usergroup']) . "'";
}
}
if ($user_list_cond) {
$user_list_cond = join($user_list_cond, ' and ');
} else {
$user_list_cond = '1';
}
$userlist_print_row = function($row) {
$hislink = getUserLink($row['username']);
echo <<<EOD
<tr>
<td>${hislink}</td>
<td>{$row['usergroup']}</td>
<td>{$row['register_time']}</td>
</tr>
EOD;
};
$cur_tab = isset($_GET['tab']) ? $_GET['tab'] : 'users';
$tabs_info = array(
'users' => array(
'name' => '用户操作',
'name' => '用户管理',
'url' => "/super-manage/users"
),
'blogs' => array(
@ -362,20 +454,12 @@ EOD;
'name' => '自定义测试',
'url' => '/super-manage/custom-test'
),
'click-zan' => array(
'name' => '点赞管理',
'url' => '/super-manage/click-zan'
),
'search' => array(
'name' => '搜索管理',
'url' => '/super-manage/search'
),
'judger' => array(
'name' => '评测机管理',
'url' => '/super-manage/judger'
),
'paste' => array(
'name' => 'Paste管理',
'name' => '剪贴板管理',
'url' => '/super-manage/paste'
)
);
@ -396,11 +480,37 @@ EOD;
<div class="col-sm-9">
<?php if ($cur_tab === 'users'): ?>
<h3>添加新用户</h3>
<?php $register_form->printHTML(); ?>
<h3>修改用户密码</h3>
<?php $change_password_form->printHTML(); ?>
<h3>用户类别设置</h3>
<?php $user_form->printHTML(); ?>
<h3>修改用户真实姓名</h3>
<?php $change_realname_form->printHTML(); ?>
<h3>封禁名单</h3>
<?php echoLongTable($banlist_cols, 'user_info', "usergroup='B'", '', $banlist_header_row, $banlist_print_row, $banlist_config) ?>
<h3>用户名单</h3>
<div id="user-query">
<form class="form-horizontal uoj-form-compressed" target="_self" method="GET">
<div class="form-group">
<label for="username" class="col-sm-2 control-label">用户名</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="username" id="user-query-username" value="" />
</div>
</div>
<div class="form-group">
<label for="usergroup" class="col-sm-2 control-label">用户类别</label>
<div class="col-sm-3">
<select class="form-control" id="user-query-usergroup" name="usergroup">
<option value="">*: 所有用户</option>
<option value="B">B: 封禁用户</option>
<option value="U">U: 普通用户</option>
<option value="S">S: 超级用户</option>
</select>
</div>
</div><div class="text-center"><button type="submit" id="user-query-submit" class="mt-2 btn btn-secondary">查询</button></div>
</form>
</div>
<?php echoLongTable($userlist_cols, 'user_info', $user_list_cond, 'order by username asc', $userlist_header_row, $userlist_print_row, $userlist_config) ?>
<?php elseif ($cur_tab === 'blogs'): ?>
<div>
<h4>添加到比赛链接</h4>
@ -455,49 +565,6 @@ EOD;
}
?>
<?= $submissions_pag->pagination() ?>
<?php elseif ($cur_tab === 'click-zan'): ?>
没写好QAQ
<?php elseif ($cur_tab === 'search'): ?>
<h2 class="text-center">一周搜索情况</h2>
<div id="search-distribution-chart-week" style="height: 250px;"></div>
<script type="text/javascript">
new Morris.Line({
element: 'search-distribution-chart-week',
data: <?= json_encode(DB::selectAll("select DATE_FORMAT(created_at, '%Y-%m-%d %h:00'), count(*) from search_requests where created_at > now() - interval 1 week group by DATE_FORMAT(created_at, '%Y-%m-%d %h:00')")) ?>,
xkey: "DATE_FORMAT(created_at, '%Y-%m-%d %h:00')",
ykeys: ["count(*)"],
labels: ['number'],
resize: true
});
</script>
<h2 class="text-center">一月搜索情况</h2>
<div id="search-distribution-chart-month" style="height: 250px;"></div>
<script type="text/javascript">
new Morris.Line({
element: 'search-distribution-chart-month',
data: <?= json_encode(DB::selectAll("select DATE_FORMAT(created_at, '%Y-%m-%d'), count(*) from search_requests where created_at > now() - interval 1 week group by DATE_FORMAT(created_at, '%Y-%m-%d')")) ?>,
xkey: "DATE_FORMAT(created_at, '%Y-%m-%d')",
ykeys: ["count(*)"],
labels: ['number'],
resize: true
});
</script>
<?php echoLongTable(array('*'), 'search_requests', "1", 'order by id desc',
'<tr><th>id</th><th>created_at</th><th>remote_addr</th><th>type</th><th>q</th><tr>',
function($row) {
echo '<tr>';
echo '<td>', $row['id'], '</td>';
echo '<td>', $row['created_at'], '</td>';
echo '<td>', $row['remote_addr'], '</td>';
echo '<td>', $row['type'], '</td>';
echo '<td>', HTML::escape($row['q']), '</td>';
echo '</tr>';
}, array(
'page_len' => 1000
))
?>
<?php elseif ($cur_tab === 'judger'): ?>
<div>
<h4>添加评测机</h4>

View File

@ -166,6 +166,11 @@
<?= HTML::js_src('/js/jquery.hotkeys.js') ?>
<?php endif ?>
<?php if (isset($REQUIRE_LIB['jquery.query'])): ?>
<!-- ckeditor -->
<?= HTML::js_src('/js/jquery.query-object.js') ?>
<?php endif ?>
<?php if (isset($REQUIRE_LIB['colorhelpers'])): ?>
<!-- colorhelpers -->
<?= HTML::js_src('/js/jquery.colorhelpers.min.js') ?>
@ -246,7 +251,9 @@
<li class="nav-item" role="presentation"><a class="nav-link" href="<?= HTML::url('/logout?_token='.crsf_token()) ?>"><?= UOJLocale::get('logout') ?></a></li>
<?php else: ?>
<li class="nav-item" role="presentation"><a class="nav-link" href="<?= HTML::url('/login') ?>"><?= UOJLocale::get('login') ?></a></li>
<?php if (!DB::selectCount("SELECT COUNT(*) FROM user_info")): ?>
<li class="nav-item" role="presentation"><a class="nav-link" href="<?= HTML::url('/register') ?>"><?= UOJLocale::get('register') ?></a></li>
<?php endif ?>
<?php endif ?>
</ul>
<h1 class="d-none d-sm-block" style="position: relative; top: 4px; width: 15em">

View File

@ -0,0 +1,247 @@
/**
* jQuery.query - Query String Modification and Creation for jQuery
* Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com)
* Licensed under the WTFPL (http://sam.zoy.org/wtfpl/).
* Date: 2009/8/13
*
* @author Blair Mitchelmore
* @version 2.2.3
*
**/
new function(settings) {
// Various Settings
var $separator = settings.separator || '&';
var $spaces = settings.spaces === false ? false : true;
var $suffix = settings.suffix === false ? '' : '[]';
var $prefix = settings.prefix === false ? false : true;
var $hash = $prefix ? settings.hash === true ? "#" : "?" : "";
var $numbers = settings.numbers === false ? false : true;
jQuery.query = new function() {
var is = function(o, t) {
return o != undefined && o !== null && (!!t ? o.constructor == t : true);
};
var parse = function(path) {
var m, rx = /\[([^[]*)\]/g, match = /^([^[]+)(\[.*\])?$/.exec(path), base = match[1], tokens = [];
while (m = rx.exec(match[2])) tokens.push(m[1]);
return [base, tokens];
};
var set = function(target, tokens, value) {
var o, token = tokens.shift();
if (typeof target != 'object') target = null;
if (token === "") {
if (!target) target = [];
if (is(target, Array)) {
target.push(tokens.length == 0 ? value : set(null, tokens.slice(0), value));
} else if (is(target, Object)) {
var i = 0;
while (target[i++] != null);
target[--i] = tokens.length == 0 ? value : set(target[i], tokens.slice(0), value);
} else {
target = [];
target.push(tokens.length == 0 ? value : set(null, tokens.slice(0), value));
}
} else if (token && token.match(/^\s*[0-9]+\s*$/)) {
var index = parseInt(token, 10);
if (!target) target = [];
target[index] = tokens.length == 0 ? value : set(target[index], tokens.slice(0), value);
} else if (token) {
var index = token.replace(/^\s*|\s*$/g, "");
if (!target) target = {};
if (is(target, Array)) {
var temp = {};
for (var i = 0; i < target.length; ++i) {
temp[i] = target[i];
}
target = temp;
}
target[index] = tokens.length == 0 ? value : set(target[index], tokens.slice(0), value);
} else {
return value;
}
return target;
};
var queryObject = function(a) {
var self = this;
self.keys = {};
if (a.queryObject) {
jQuery.each(a.get(), function(key, val) {
self.SET(key, val);
});
} else {
self.parseNew.apply(self, arguments);
}
return self;
};
queryObject.prototype = {
queryObject: true,
parseNew: function(){
var self = this;
self.keys = {};
jQuery.each(arguments, function() {
var q = "" + this;
q = q.replace(/^[?#]/,''); // remove any leading ? || #
q = q.replace(/[;&]$/,''); // remove any trailing & || ;
if ($spaces) q = q.replace(/[+]/g,' '); // replace +'s with spaces
jQuery.each(q.split(/[&;]/), function(){
var key = decodeURIComponent(this.split('=')[0] || "");
var val = decodeURIComponent(this.split('=')[1] || "");
if (!key) return;
if ($numbers) {
if (/^[+-]?[0-9]+\.[0-9]*$/.test(val)) // simple float regex
val = parseFloat(val);
else if (/^[+-]?[1-9][0-9]*$/.test(val)) // simple int regex
val = parseInt(val, 10);
}
val = (!val && val !== 0) ? true : val;
self.SET(key, val);
});
});
return self;
},
has: function(key, type) {
var value = this.get(key);
return is(value, type);
},
GET: function(key) {
if (!is(key)) return this.keys;
var parsed = parse(key), base = parsed[0], tokens = parsed[1];
var target = this.keys[base];
while (target != null && tokens.length != 0) {
target = target[tokens.shift()];
}
return typeof target == 'number' ? target : target || "";
},
get: function(key) {
var target = this.GET(key);
if (is(target, Object))
return jQuery.extend(true, {}, target);
else if (is(target, Array))
return target.slice(0);
return target;
},
SET: function(key, val) {
if(!key.includes("__proto__")){
var value = !is(val) ? null : val;
var parsed = parse(key), base = parsed[0], tokens = parsed[1];
var target = this.keys[base];
this.keys[base] = set(target, tokens.slice(0), value);
}
return this;
},
set: function(key, val) {
return this.copy().SET(key, val);
},
REMOVE: function(key, val) {
if (val) {
var target = this.GET(key);
if (is(target, Array)) {
for (tval in target) {
target[tval] = target[tval].toString();
}
var index = $.inArray(val, target);
if (index >= 0) {
key = target.splice(index, 1);
key = key[index];
} else {
return;
}
} else if (val != target) {
return;
}
}
return this.SET(key, null).COMPACT();
},
remove: function(key, val) {
return this.copy().REMOVE(key, val);
},
EMPTY: function() {
var self = this;
jQuery.each(self.keys, function(key, value) {
delete self.keys[key];
});
return self;
},
load: function(url) {
var hash = url.replace(/^.*?[#](.+?)(?:\?.+)?$/, "$1");
var search = url.replace(/^.*?[?](.+?)(?:#.+)?$/, "$1");
return new queryObject(url.length == search.length ? '' : search, url.length == hash.length ? '' : hash);
},
empty: function() {
return this.copy().EMPTY();
},
copy: function() {
return new queryObject(this);
},
COMPACT: function() {
function build(orig) {
var obj = typeof orig == "object" ? is(orig, Array) ? [] : {} : orig;
if (typeof orig == 'object') {
function add(o, key, value) {
if (is(o, Array))
o.push(value);
else
o[key] = value;
}
jQuery.each(orig, function(key, value) {
if (!is(value)) return true;
add(obj, key, build(value));
});
}
return obj;
}
this.keys = build(this.keys);
return this;
},
compact: function() {
return this.copy().COMPACT();
},
toString: function() {
var i = 0, queryString = [], chunks = [], self = this;
var encode = function(str) {
str = str + "";
str = encodeURIComponent(str);
if ($spaces) str = str.replace(/%20/g, "+");
return str;
};
var addFields = function(arr, key, value) {
if (!is(value) || value === false) return;
var o = [encode(key)];
if (value !== true) {
o.push("=");
o.push(encode(value));
}
arr.push(o.join(""));
};
var build = function(obj, base) {
var newKey = function(key) {
return !base || base == "" ? [key].join("") : [base, "[", key, "]"].join("");
};
jQuery.each(obj, function(key, value) {
if (typeof value == 'object')
build(value, newKey(key));
else
addFields(chunks, newKey(key), value);
});
};
build(this.keys);
if (chunks.length > 0) queryString.push($hash);
queryString.push(chunks.join($separator));
return queryString.join("");
}
};
return new queryObject(location.search, location.hash);
};
}(jQuery.query || {}); // Pass in jQuery.query as settings object