refactor(web/user/edit): user_edit_v2

This commit is contained in:
Baoshuo Ren 2022-10-19 21:59:16 +08:00
parent 07b3388f56
commit e33e3ef413
Signed by: baoshuo
GPG Key ID: 00CB9680AB29F51A
11 changed files with 302 additions and 196 deletions

View File

@ -816,6 +816,7 @@ CREATE TABLE `user_info` (
`last_login` timestamp NOT NULL DEFAULT 0, `last_login` timestamp NOT NULL DEFAULT 0,
`last_visited` timestamp NOT NULL DEFAULT 0, `last_visited` timestamp NOT NULL DEFAULT 0,
`images_size_limit` int(11) UNSIGNED NOT NULL DEFAULT 104857600, /* 100 MiB */ `images_size_limit` int(11) UNSIGNED NOT NULL DEFAULT 104857600, /* 100 MiB */
`codeforces_handle` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
PRIMARY KEY (`username`), PRIMARY KEY (`username`),
KEY `ac_num` (`ac_num`,`username`) KEY `ac_num` (`ac_num`,`username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;

View File

@ -1,4 +1,8 @@
<?php <?php
requireLib('bootstrap5');
requireLib('md5');
requirePHPLib('form');
if (!Auth::check()) { if (!Auth::check()) {
redirectToLogin(); redirectToLogin();
} }
@ -11,202 +15,281 @@
become403Page(); become403Page();
} }
function handlePost() { if (isset($_GET['tab'])) {
global $myUser, $user; $cur_tab = $_GET['tab'];
if ($user['username'] == Auth::id()) { } else {
if (!isset($_POST['old_password'])) { $cur_tab = 'profile';
return '无效表单'; }
}
$old_password = $_POST['old_password']; $tabs_info = [
if (!validatePassword($old_password) || !checkPassword($user, $old_password)) { 'profile' => [
return "失败:密码错误。"; 'name' => '<i class="bi bi-person-fill"></i> 个人资料',
} 'url' => "/user/{$user['username']}/edit/profile",
} ],
if ($_POST['ptag']) { 'password' => [
$password = $_POST['password']; 'name' => '<i class="bi bi-key-fill"></i> 修改密码',
if (!validatePassword($password)) { 'url' => "/user/{$user['username']}/edit/password",
return "失败:无效密码。"; ],
} ];
$password = getPasswordToStore($password, $user['username']);
DB::update("update user_info set password = '$password' where username = '{$user['username']}'"); if (!isset($tabs_info[$cur_tab])) {
} become404Page();
}
$email = $_POST['email']; if ($cur_tab == 'profile') {
if (!validateEmail($email)) { $update_profile_form = new UOJForm('update_profile');
return "失败:无效电子邮箱。"; $username = UOJLocale::get('username');
} $avatar = UOJLocale::get('avatar');
$esc_email = DB::escape($email); $change_avatar_help = UOJLocale::get('change avatar help');
DB::update("update user_info set email = '$esc_email' where username = '{$user['username']}'"); $update_profile_form->appendHTML(<<<EOD
<div class="mb-3">
<label for="input-username" class="form-label">$username</label>
<input type="text" class="form-control" id="input-username" aria-describedby="help-username" value="{$user['username']}" disabled>
<div id="help-username" class="form-text">用户名不能被修改。</div>
</div>
<div class="mb-3">
<div>$avatar</div>
<div class="mt-1 small text-muted">$change_avatar_help</div>
</div>
EOD);
$update_profile_form->addVInput('email', 'email', UOJLocale::get('email'), $user['email'],
function($email, &$vdata) {
if (!validateEmail($email)) {
return 'Email 格式不合法。';
}
if ($_POST['Qtag']) { $vdata['email'] = $email;
$qq = $_POST['qq'];
if (!validateQQ($qq)) { return '';
return "失败无效QQ。"; }, null);
} $update_profile_form->addVInput('qq', 'text', UOJLocale::get('QQ'), $user['qq'] == 0 ? '' : $user['qq'],
$esc_qq = DB::escape($qq); function($qq, &$vdata) {
DB::update("update user_info set qq = '$esc_qq' where username = '{$user['username']}'"); if ($qq && !validateQQ($qq)) {
return 'QQ 格式不合法。';
}
$vdata['qq'] = $qq;
return '';
}, null);
if (isSuperUser($myUser)) {
$update_profile_form->addVInput('school', 'text', UOJLocale::get('school'), $user['school'],
function($school, &$vdata) {
$vdata['school'] = $school;
return '';
}, null);
} else { } else {
DB::update("update user_info set QQ = NULL where username = '{$user['username']}'"); $school = UOJLocale::get('school');
$update_profile_form->appendHTML(<<<EOD
<div class="mb-3">
<label for="input-school" class="form-label">$school</label>
<input type="text" class="form-control" id="input-school" aria-describedby="help-school" value="{$user['school']}" disabled>
<div id="help-school" class="form-text">只有管理员才能修改用户所属学校。</div>
</div>
EOD);
} }
if ($_POST['sex'] == "U" || $_POST['sex'] == 'M' || $_POST['sex'] == 'F') { $update_profile_form->addVSelect('sex', [
$sex = $_POST['sex']; 'U' => UOJLocale::get('refuse to answer'),
$esc_sex = DB::escape($sex); 'M' => UOJLocale::get('male'),
DB::update("update user_info set sex = '$esc_sex' where username = '{$user['username']}'"); 'F' => UOJLocale::get('female'),
], UOJLocale::get('sex'), $user['sex']);
$update_profile_form->addVInput('motto', 'text', UOJLocale::get('motto'), $user['motto'],
function($motto, &$vdata) {
if (!validateMotto($motto)) {
return '格言格式不合法';
}
$vdata['motto'] = $motto;
return '';
}, null);
$update_profile_form->addVInput('codeforces_handle', 'text', UOJLocale::get('codeforces handle'), $user['codeforces_handle'],
function($codeforces_handle, &$vdata) {
if ($codeforces_handle && !validateUsername($codeforces_handle)) {
return 'Codeforces 用户名格式不合法。';
}
$vdata['codeforces_handle'] = $codeforces_handle;
return '';
}, null);
$update_profile_form->handle = function(&$vdata) use ($user, $myUser) {
$esc_email = DB::escape($vdata['email']);
$esc_qq = DB::escape($vdata['qq']);
$esc_sex = DB::escape($vdata['sex']);
$esc_motto = DB::escape($vdata['motto']);
$esc_codeforces_handle = DB::escape($vdata['codeforces_handle']);
if (isSuperUser($myUser)) {
$esc_school = DB::escape($vdata['school']);
DB::update("UPDATE user_info SET school = '$esc_school' WHERE username = '{$user['username']}'");
}
DB::update("UPDATE user_info SET email = '$esc_email', qq = '$esc_qq', sex = '$esc_sex', motto = '$esc_motto', codeforces_handle = '$esc_codeforces_handle' WHERE username = '{$user['username']}'");
};
$update_profile_form->submit_button_config['margin_class'] = 'mt-3';
$update_profile_form->submit_button_config['text'] = '更新';
$update_profile_form->runAtServer();
} elseif ($cur_tab == 'password') {
if (isset($_POST['submit-change_password']) && $_POST['submit-change_password'] == 'change_password') {
header('Content-Type: application/json');
$old_password = $_POST['current_password'];
$new_password = $_POST['new_password'];
if (!validatePassword($old_password) || !checkPassword($user, $old_password)) {
die(json_encode(['status' => 'error', 'message' => '旧密码错误']));
}
if (!validatePassword($new_password)) {
die(json_encode(['status' => 'error', 'message' => '新密码不合法']));
}
if ($old_password == $new_password) {
die(json_encode(['status' => 'error', 'message' => '新密码不能与旧密码相同']));
}
$password = getPasswordToStore($new_password, $user['username']);
DB::update("UPDATE `user_info` SET `password` = '$password' where `username` = '{$user['username']}'");
die(json_encode(['status' => 'success', 'message' => '密码修改成功']));
} }
if (validateMotto($_POST['motto'])) {
$esc_motto = DB::escape($_POST['motto']);
DB::update("update user_info set motto = '$esc_motto' where username = '{$user['username']}'");
}
return "ok";
}
if (isset($_POST['change'])) {
die(handlePost());
} }
$pageTitle = $user['username'] == $myUser['username']
? UOJLocale::get('modify my profile')
: UOJLocale::get('modify his profile', $user['username'])
?> ?>
<?php
$REQUIRE_LIB['dialog'] = ''; <?php echoUOJPageHeader($pageTitle) ?>
$REQUIRE_LIB['md5'] = '';
?> <h1 class="h2">
<?php echoUOJPageHeader(UOJLocale::get('modify my profile')) ?> <?= $pageTitle ?>
<h2 class="page-header"> </h1>
<?php if ($user['username'] == Auth::id()): ?>
<?= UOJLocale::get('modify my profile') ?> <div class="row mt-4">
<?php else: ?> <!-- left col -->
修改 <?= $user['username'] ?> 的个人信息 <div class="col-md-3">
<?php endif ?>
</h2> <div class="list-group">
<?php if (isSuperUser($myUser)): ?> <?php foreach ($tabs_info as $id => $tab): ?>
<p>您正在使用管理特权修改 <?= $user['username'] ?> 的个人信息。</p> <a
role="button"
class="list-group-item list-group-item-action <?= $cur_tab == $id ? 'active' : '' ?>"
href="<?= $tab['url'] ?>">
<?= $tab['name'] ?>
</a>
<?php endforeach ?>
</div>
<a
class="btn btn-light d-block mt-2 w-100 text-start text-primary"
style="--bs-btn-hover-bg: #d3d4d570; --bs-btn-hover-border-color: transparent;"
href="<?= HTML::url("/user/{$user['username']}") ?>">
<i class="bi bi-arrow-left"></i> 返回
</a>
<?php if (isSuperUser($myUser) && $user['username'] != $myUser['username']): ?>
<div class="alert alert-warning mt-3 small" role="alert">
您正在使用管理特权查看并编辑其它用户的资料。
</div>
<?php endif ?> <?php endif ?>
<form id="form-update" class="form-horizontal">
<?php if ($user['username'] == Auth::id()): ?>
<h4><?= UOJLocale::get('please enter your password for authorization') ?></h4>
<div id="div-old_password" class="form-group">
<label for="input-old_password" class="col-sm-2 control-label"><?= UOJLocale::get('password') ?></label>
<div class="col-sm-3">
<input type="password" class="form-control" name="old_password" id="input-old_password" placeholder="<?= UOJLocale::get('enter your password') ?>" maxlength="20" />
<span class="help-block" id="help-old_password"></span>
</div>
</div>
<?php endif ?>
<h4><?= UOJLocale::get('please enter your new profile') ?></h4>
<div id="div-password" class="form-group">
<label for="input-password" class="col-sm-2 control-label"><?= UOJLocale::get('new password') ?></label>
<div class="col-sm-3">
<input type="password" class="form-control" id="input-password" name="password" placeholder="<?= UOJLocale::get('enter your new password') ?>" maxlength="20" />
<input type="password" class="form-control top-buffer-sm" id="input-confirm_password" placeholder="<?= UOJLocale::get('re-enter your new password') ?>" maxlength="20" />
<span class="help-block" id="help-password"><?= UOJLocale::get('leave it blank if you do not want to change the password') ?></span>
</div>
</div>
<div id="div-email" class="form-group">
<label for="input-email" class="col-sm-2 control-label"><?= UOJLocale::get('email') ?></label>
<div class="col-sm-3">
<input type="email" class="form-control" name="email" id="input-email" value="<?=$user['email']?>" placeholder="<?= UOJLocale::get('enter your email') ?>" maxlength="50" />
<span class="help-block" id="help-email"></span>
</div>
</div>
<div id="div-qq" class="form-group">
<label for="input-qq" class="col-sm-2 control-label"><?= UOJLocale::get('QQ') ?></label>
<div class="col-sm-3">
<input type="text" class="form-control" name="qq" id="input-qq" value="<?= $user['qq'] != 0 ? $user['qq'] : '' ?>" placeholder="<?= UOJLocale::get('enter your QQ') ?>" maxlength="50" />
<span class="help-block" id="help-qq"></span>
</div>
</div>
<div id="div-sex" class="form-group">
<label for="input-sex" class="col-sm-2 control-label"><?= UOJLocale::get('sex') ?></label>
<div class="col-sm-3">
<select class="form-control" id="input-sex" name="sex">
<option value="U"<?= $user['sex'] == 'U' ? ' selected="selected"' : ''?>><?= UOJLocale::get('refuse to answer') ?></option>
<option value="M"<?= $user['sex'] == 'M' ? ' selected="selected"' : ''?>><?= UOJLocale::get('male') ?></option>
<option value="F"<?= $user['sex'] == 'F' ? ' selected="selected"' : ''?>><?= UOJLocale::get('female') ?></option>
</select>
</div>
</div>
<div id="div-motto" class="form-group">
<label for="input-motto" class="col-sm-2 control-label"><?= UOJLocale::get('motto') ?></label>
<div class="col-sm-3">
<textarea class="form-control" id="input-motto" name="motto"><?=HTML::escape($user['motto'])?></textarea>
<span class="help-block" id="help-motto">格言支持 Markdown 语法。</span>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-3">
<p class="form-control-static"><strong><?= UOJLocale::get('change avatar help') ?></strong></p>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-3">
<button type="submit" id="button-submit" class="btn btn-secondary"><?= UOJLocale::get('submit') ?></button>
</div>
</div>
</form>
<script type="text/javascript"> </div>
function validateUpdatePost() { <!-- end left col -->
var ok = true;
ok &= getFormErrorAndShowHelp('email', validateEmail);
<?php if ($user['username'] == Auth::id()): ?> <!-- right col -->
ok &= getFormErrorAndShowHelp('old_password', validatePassword); <div class="col-md-9">
<?php endif ?> <?php if ($cur_tab == 'profile'): ?>
<div class="card">
<div class="card-body">
<?php $update_profile_form->printHTML() ?>
</div>
</div>
<?php elseif ($cur_tab == 'password'): ?>
<div class="card">
<div class="card-body">
<div id="result-alert" class="alert" role="alert" style="display: none"></div>
<form method="post" id="form-change_password">
<div class="mb-3">
<label for="input-current_password" class="form-label">
<?= UOJLocale::get('current password') ?>
</label>
<input type="password" class="form-control" id="input-current_password" placeholder="<?= UOJLocale::get('enter your password') ?>" maxlength="20">
<div id="help-current_password" class="invalid-feedback"></div>
</div>
<div class="mb-3">
<label for="input-new_password" class="form-label">
<?= UOJLocale::get('new password') ?>
</label>
<input type="password" class="form-control" id="input-new_password" placeholder="<?= UOJLocale::get('enter your new password') ?>" maxlength="20">
<div id="help-new_password" class="invalid-feedback"></div>
</div>
<div class="mb-3">
<label for="input-confirm_password" class="form-label">
<?= UOJLocale::get('confirm new password') ?>
</label>
<input type="password" class="form-control" id="input-confirm_password" placeholder="<?= UOJLocale::get('re-enter your new password') ?>" maxlength="20">
<div id="help-confirm_password" class="invalid-feedback"></div>
</div>
<?php if (isSuperUser($myUser) && $user['username'] != $myUser['username']): ?>
<div class="alert alert-warning mb-0" role="alert">
如需修改其他用户的密码,请前往 <a href="/super-manage/users" class="alert-link">系统管理</a> 页面操作。
</div>
<?php endif ?>
<div class="text-center">
<button type="submit" id="button-submit-change_password" name="submit-change_password" value="change_password" class="mt-3 btn btn-secondary">更新</button>
</div>
</form>
</div>
</div>
<script>
$('#form-change_password').submit(function() {
var ok = true;
if ($('#input-password').val().length > 0) ok &= getFormErrorAndShowHelp('current_password', validatePassword);
ok &= getFormErrorAndShowHelp('password', validateSettingPassword); ok &= getFormErrorAndShowHelp('new_password', validateSettingPassword);
if ($('#input-qq').val().length > 0)
ok &= getFormErrorAndShowHelp('qq', validateQQ); if (ok) {
ok &= getFormErrorAndShowHelp('motto', validateMotto); $.ajax({
return ok; method: 'POST',
} data: {
function submitUpdatePost() { 'submit-change_password': 'change_password',
if (!validateUpdatePost()) 'current_password': md5($('#input-current_password').val(), "<?= getPasswordClientSalt() ?>"),
return; 'new_password': md5($('#input-new_password').val(), "<?= getPasswordClientSalt() ?>"),
$.post('', { },
change : '', success: function(res) {
etag : $('#input-email').val().length, if (res.status === 'success') {
ptag : $('#input-password').val().length, $('#result-alert')
Qtag : $('#input-qq').val().length, .html('密码修改成功!')
email : $('#input-email').val(), .addClass('alert-success')
password : md5($('#input-password').val(), "<?= getPasswordClientSalt() ?>"), .removeClass('alert-danger')
<?php if ($user['username'] == Auth::id()): ?> .show();
old_password : md5($('#input-old_password').val(), "<?= getPasswordClientSalt() ?>"), } else {
<?php endif ?> $('#result-alert')
qq : $('#input-qq').val(), .html('密码修改失败。' + (res.message || ''))
sex : $('#input-sex').val(), .removeClass('alert-success')
motto : $('#input-motto').val() .addClass('alert-danger')
}, function(msg) { .show();
if (msg == 'ok') {
BootstrapDialog.show({
title : '修改成功',
message : '用户信息修改成功',
type : BootstrapDialog.TYPE_SUCCESS,
buttons : [{
label: '好的',
action: function(dialog) {
dialog.close();
} }
}], },
onhidden : function(dialog) { error: function() {
window.location.href = '/user/<?=$user['username']?>'; $('#result-alert')
.html('密码修改失败:请求失败。')
.removeClass('alert-success')
.addClass('alert-danger')
.show();
} }
}); });
} else {
BootstrapDialog.show({
title : '修改失败',
message : msg,
type : BootstrapDialog.TYPE_DANGER,
buttons: [{
label: '好的',
action: function(dialog) {
dialog.close();
}
}],
});
} }
return false;
}); });
} </script>
$(document).ready(function(){$('#form-update').submit(function(e) {submitUpdatePost();e.preventDefault();}); <?php endif ?>
}); <!-- end right col -->
</script> </div>
</div>
<?php echoUOJPageFooter() ?> <?php echoUOJPageFooter() ?>

View File

@ -159,7 +159,7 @@ EOD;
public function addVSelect($name, $options, $label_text, $default_value) { public function addVSelect($name, $options, $label_text, $default_value) {
$default_value = htmlspecialchars($default_value); $default_value = htmlspecialchars($default_value);
$html = <<<EOD $html = <<<EOD
<div id="div-$name"> <div id="div-$name" class="mb-3">
<label for="input-$name" class="control-label">$label_text</label> <label for="input-$name" class="control-label">$label_text</label>
<select class="form-control form-select" id="input-{$name}" name="$name"> <select class="form-control form-select" id="input-{$name}" name="$name">
@ -534,14 +534,15 @@ EOD;
if ($field['validator_js'] != 'always_ok') { if ($field['validator_js'] != 'always_ok') {
echo <<<EOD echo <<<EOD
if (${field['name']}_err) { if (${field['name']}_err) {
$('#div-${field['name']}').addClass('has-error'); $('#div-${field['name']}').addClass('has-error'); // for bootstrap4
$('#input-${field['name']}').addClass('is-invalid');
$('#help-${field['name']}').text(${field['name']}_err); $('#help-${field['name']}').text(${field['name']}_err);
ok = false; ok = false;
} else { } else {
$('#div-${field['name']}').removeClass('has-error'); $('#div-${field['name']}').removeClass('has-error'); // for bootstrap4
$('#input-${field['name']}').removeClass('is-invalid');
$('#help-${field['name']}').text(''); $('#help-${field['name']}').text('');
} }
EOD; EOD;
} }
} }
@ -562,11 +563,13 @@ EOD;
$(this).find("input[type='file']").each(function() { $(this).find("input[type='file']").each(function() {
for (var i = 0; i < this.files.length; i++) { for (var i = 0; i < this.files.length; i++) {
if (this.files[i].size > 10 * 1024 * 1024) { if (this.files[i].size > 10 * 1024 * 1024) {
$('#div-' + $(this).attr('name')).addClass('has-error'); $('#div-' + $(this).attr('name')).addClass('has-error'); // for bootstrap4
$('#input-' + $(this).attr('name')).addClass('is-invalid');
$('#help-' + $(this).attr('name')).text('文件大小不能超过10M'); $('#help-' + $(this).attr('name')).text('文件大小不能超过10M');
ok = false; ok = false;
} else { } else {
$('#div-' + $(this).attr('name')).removeClass('has-error'); $('#div-' + $(this).attr('name')).removeClass('has-error'); // for bootstrap4
$('#input-' + $(this).attr('name')).removeClass('is-invalid');
$('#help-' + $(this).attr('name')).text(''); $('#help-' + $(this).attr('name')).text('');
} }
} }

View File

@ -9,6 +9,7 @@ return [
'private message' => 'Private Message', 'private message' => 'Private Message',
'system message' => 'System Message', 'system message' => 'System Message',
'system manage' => 'System Manage', 'system manage' => 'System Manage',
'avatar' => 'Avatar',
'contests' => 'Contests', 'contests' => 'Contests',
'problems' => 'Problems', 'problems' => 'Problems',
'problems lists' => 'Problems Lists', 'problems lists' => 'Problems Lists',
@ -35,11 +36,15 @@ return [
'username' => 'Username', 'username' => 'Username',
'password' => 'Password', 'password' => 'Password',
'new password' => 'New password', 'new password' => 'New password',
'current password' => 'Current password',
'confirm new password' => 'Confirm new password',
'verification code' => 'Verification code', 'verification code' => 'Verification code',
'email' => 'Email', 'email' => 'Email',
'QQ' => 'QQ', 'QQ' => 'QQ',
'school' => 'School',
'sex' => 'Sex', 'sex' => 'Sex',
'motto' => 'Motto', 'motto' => 'Motto',
'codeforces handle' => 'Codeforces handle',
'view all' => 'View all', 'view all' => 'View all',
'hidden' => 'Hidden', 'hidden' => 'Hidden',
'appraisal' => 'Appraisal', 'appraisal' => 'Appraisal',
@ -58,6 +63,9 @@ return [
'user profile' => 'User profile', 'user profile' => 'User profile',
'send private message' => 'Send private message', 'send private message' => 'Send private message',
'modify my profile' => 'Modify my profile', 'modify my profile' => 'Modify my profile',
'modify his profile' => function($name) {
return "Modify $name's profile";
},
'visit his blog' => function($name) { 'visit his blog' => function($name) {
return "Visit $name's blog"; return "Visit $name's blog";
}, },
@ -68,7 +76,7 @@ return [
'please enter your password for authorization' => 'Please enter your password for authorization', 'please enter your password for authorization' => 'Please enter your password for authorization',
'please enter your new profile' => 'Please enter your new profile', 'please enter your new profile' => 'Please enter your new profile',
'leave it blank if you do not want to change the password' => 'Leave it blank if you do not want to change the password', 'leave it blank if you do not want to change the password' => 'Leave it blank if you do not want to change the password',
'change avatar help' => 'Do you want to change your avatar? Please see <a href="/faq">Help</a>', 'change avatar help' => 'Do you want to change your avatar? Please see <a class="text-decoration-none" href="/faq">Help</a>',
'enter your username' => 'Enter your username', 'enter your username' => 'Enter your username',
'enter your email' => 'Enter your email', 'enter your email' => 'Enter your email',
'enter your password' => 'Enter your password', 'enter your password' => 'Enter your password',

View File

@ -9,6 +9,7 @@ return [
'private message' => '私信', 'private message' => '私信',
'system message' => '系统消息', 'system message' => '系统消息',
'system manage' => '系统管理', 'system manage' => '系统管理',
'avatar' => '头像',
'contests' => '比赛', 'contests' => '比赛',
'problems' => '题库', 'problems' => '题库',
'problems lists' => '题单', 'problems lists' => '题单',
@ -35,11 +36,15 @@ return [
'username' => '用户名', 'username' => '用户名',
'password' => '密码', 'password' => '密码',
'new password' => '新密码', 'new password' => '新密码',
'current password' => '当前密码',
'confirm new password' => '确认新密码',
'verification code' => '验证码', 'verification code' => '验证码',
'email' => 'Email', 'email' => 'Email',
'QQ' => 'QQ', 'QQ' => 'QQ',
'school' => '学校',
'sex' => '性别', 'sex' => '性别',
'motto' => '格言', 'motto' => '格言',
'codeforces handle' => 'Codeforces 用户名',
'view all' => '查看全部', 'view all' => '查看全部',
'hidden' => '隐藏', 'hidden' => '隐藏',
'appraisal' => '评价', 'appraisal' => '评价',
@ -58,6 +63,9 @@ return [
'user profile' => '用户信息', 'user profile' => '用户信息',
'send private message' => '发送私信', 'send private message' => '发送私信',
'modify my profile' => '更改个人信息', 'modify my profile' => '更改个人信息',
'modify his profile' => function($name) {
return "更改 $name 的个人信息";
},
'visit his blog' => function($name) { 'visit his blog' => function($name) {
return "访问 $name 的博客"; return "访问 $name 的博客";
}, },
@ -68,7 +76,7 @@ return [
'please enter your password for authorization' => '请输入您的密码进行身份验证', 'please enter your password for authorization' => '请输入您的密码进行身份验证',
'please enter your new profile' => '请输入新的个人信息', 'please enter your new profile' => '请输入新的个人信息',
'leave it blank if you do not want to change the password' => '如果不想修改密码请留空', 'leave it blank if you do not want to change the password' => '如果不想修改密码请留空',
'change avatar help' => '想改头像?见<a href="/faq">帮助</a>', 'change avatar help' => '想改头像?见 <a class="text-decoration-none" href="/faq">帮助</a>',
'enter your username' => '输入用户名', 'enter your username' => '输入用户名',
'enter your email' => '输入 Email', 'enter your email' => '输入 Email',
'enter your password' => '输入密码', 'enter your password' => '输入密码',

View File

@ -24,14 +24,14 @@ class HTML {
return '<input type="hidden" name="_token" value="'.crsf_token().'" />'; return '<input type="hidden" name="_token" value="'.crsf_token().'" />';
} }
public static function div_vinput($name, $type, $label_text, $default_value) { public static function div_vinput($name, $type, $label_text, $default_value) {
return '<div id="'."div-$name".'">' return '<div id="'."div-$name".'" class="mb-3">'
. '<label for="'."input-$name".'" class="control-label">'.$label_text.'</label>' . '<label for="'."input-$name".'" class="control-label form-label">'.$label_text.'</label>'
. '<input type="'.$type.'" class="form-control" name="'.$name.'" id="'."input-$name".'" value="'.HTML::escape($default_value).'" />' . '<input type="'.$type.'" class="form-control" name="'.$name.'" id="'."input-$name".'" value="'.HTML::escape($default_value).'" />'
. '<span class="help-block" id="'."help-$name".'"></span>' . '<span class="help-block invalid-feedback" id="'."help-$name".'"></span>'
. '</div>'; . '</div>';
} }
public static function div_vtextarea($name, $label_text, $default_value) { public static function div_vtextarea($name, $label_text, $default_value) {
return '<div id="'."div-$name".'">' return '<div id="'."div-$name".'" class="mb-3">'
. '<label for="'."input-$name".'" class="control-label">'.$label_text.'</label>' . '<label for="'."input-$name".'" class="control-label">'.$label_text.'</label>'
. '<textarea class="form-control" name="'.$name.'" id="'."input-$name".'">'.HTML::escape($default_value).'</textarea>' . '<textarea class="form-control" name="'.$name.'" id="'."input-$name".'">'.HTML::escape($default_value).'</textarea>'
. '<span class="help-block" id="'."help-$name".'"></span>' . '<span class="help-block" id="'."help-$name".'"></span>'

View File

@ -105,7 +105,7 @@ class Upgrader {
public static function upgradeToLatest() { public static function upgradeToLatest() {
$names = array_filter(scandir(self::upgraderRoot()), function ($name) { $names = array_filter(scandir(self::upgraderRoot()), function ($name) {
return is_dir(self::upgraderRoot().'/'.$name) && preg_match('/^\d+_[a-zA-Z_]+$/', $name); return is_dir(self::upgraderRoot().'/'.$name) && preg_match('/^\d+_[0-9a-zA-Z_]+$/', $name);
}); });
natsort($names); natsort($names);

View File

@ -72,7 +72,7 @@ Route::group([
Route::any('/reset-password', '/reset_pw.php'); Route::any('/reset-password', '/reset_pw.php');
Route::any('/user/{username}', '/user_info.php'); Route::any('/user/{username}', '/user_info.php');
Route::any('/user/{username}/edit', '/user_info_edit.php'); Route::any('/user/{username}/edit(?:/{tab})?', '/user_info_edit.php');
Route::any('/user_msg', '/user_msg.php'); Route::any('/user_msg', '/user_msg.php');
Route::any('/user/{username}/system_msg', '/user_system_msg.php'); Route::any('/user/{username}/system_msg', '/user_system_msg.php');

View File

@ -0,0 +1 @@
ref: https://github.com/renbaoshuo/S2OJ/pull/6

View File

@ -0,0 +1 @@
ALTER TABLE `user_info` DROP COLUMN IF EXISTS `codeforces_handle`;

View File

@ -0,0 +1 @@
ALTER TABLE `user_info` ADD COLUMN `codeforces_handle` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';