Add a option for requiring player name when register

This commit is contained in:
Pig Fang 2018-08-17 17:03:38 +08:00
parent 939d71923b
commit 4a72442fdb
12 changed files with 214 additions and 19 deletions

View File

@ -172,6 +172,7 @@ class AdminController extends Controller
});
$form->checkbox('user_can_register')->label();
$form->checkbox('register_with_player_name')->label();
$form->checkbox('require_verification')->label();
$form->text('regs_per_ip');

View File

@ -11,6 +11,7 @@ use Cache;
use Session;
use App\Events;
use App\Models\User;
use App\Models\Player;
use App\Mail\ForgotPassword;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
@ -91,23 +92,33 @@ class AuthController extends Controller
public function handleRegister(Request $request)
{
$data = $this->validate($request, [
'email' => 'required|email|unique:users',
'password' => 'required|min:8|max:32',
'nickname' => 'required|no_special_chars|max:255',
'captcha' => 'required'.(app()->environment('testing') ? '' : '|captcha')
]);
if (! option('user_can_register')) {
return json(trans('auth.register.close'), 7);
}
$rule = option('register_with_player_name') ?
['player_name' => 'required|player_name|min:'.option('player_name_length_min').'|max:'.option('player_name_length_max')] :
['nickname' => 'required|no_special_chars|max:255'];
$data = $this->validate($request, array_merge([
'email' => 'required|email|unique:users',
'password' => 'required|min:8|max:32',
'captcha' => 'required'.(app()->environment('testing') ? '' : '|captcha')
], $rule));
if (option('register_with_player_name')) {
event(new Events\CheckPlayerExists($request->get('player_name')));
if (Player::where('player_name', $request->get('player_name'))->first()) {
return json(trans('user.player.add.repeated'), 2);
}
}
// If amount of registered accounts of IP is more than allowed amounts,
// reject the registration.
if (User::where('ip', Utils::getClientIp())->count() < option('regs_per_ip')) {
$user = new User;
$user->email = $data['email'];
$user->nickname = $data['nickname'];
$user->nickname = $data[option('register_with_player_name') ? 'player_name' : 'nickname'];
$user->score = option('user_initial_score');
$user->avatar = 0;
$user->password = User::getEncryptedPwdFromEvent($data['password'], $user)
@ -121,11 +132,22 @@ class AuthController extends Controller
event(new Events\UserRegistered($user));
if (option('register_with_player_name')) {
$player = new Player;
$player->uid = $user->uid;
$player->player_name = $request->get('player_name');
$player->preference = 'default';
$player->last_modified = Utils::getTimeFormatted();
$player->save();
event(new Events\PlayerWasAdded($player));
}
Auth::login($user);
return json([
'errno' => 0,
'msg' => trans('auth.register.success')
'errno' => 0,
'msg' => trans('auth.register.success')
]);
} else {

View File

@ -5,6 +5,7 @@ return [
'site_name' => 'Blessing Skin',
'site_description' => 'Open-source PHP Minecraft Skin Hosting Service',
'user_can_register' => 'true',
'register_with_player_name' => 'true',
'require_verification' => 'false',
'regs_per_ip' => '3',
'ip_get_method' => '0',

View File

@ -32,6 +32,23 @@
</div>
<div
v-if="requirePlayer"
class="form-group has-feedback"
:title="$t('auth.player-name-intro')"
data-placement="top"
data-toggle="tooltip"
>
<input
v-model="playerName"
type="text"
class="form-control"
:placeholder="$t('auth.player-name')"
ref="playerName"
>
<span class="glyphicon glyphicon-pencil form-control-feedback"></span>
</div>
<div
v-else
class="form-group has-feedback"
:title="$t('auth.nickname-intro')"
data-placement="top"
@ -108,16 +125,18 @@ export default {
password: '',
confirm: '',
nickname: '',
playerName: '',
captcha: '',
time: Date.now(),
infoMsg: '',
warningMsg: '',
pending: false
pending: false,
requirePlayer: __bs_data__.player
}),
methods: {
async submit() {
const {
email, password, confirm, nickname, captcha
email, password, confirm, playerName, nickname, captcha
} = this;
if (!email) {
@ -150,7 +169,13 @@ export default {
return;
}
if (!nickname) {
if (this.requirePlayer && !playerName) {
this.infoMsg = this.$t('auth.emptyPlayerName');
this.$refs.playerName.focus();
return;
}
if (!this.requirePlayer && !nickname) {
this.infoMsg = this.$t('auth.emptyNickname');
this.$refs.nickname.focus();
return;
@ -165,7 +190,11 @@ export default {
this.pending = true;
const { errno, msg } = await this.$http.post(
'/auth/register',
{ email, password, nickname, captcha }
Object.assign(
{},
{ email, password, captcha },
this.requirePlayer ? { player_name: playerName } : { nickname }
)
);
if (errno === 0) {
swal({ type: 'success', text: msg });

View File

@ -1,6 +1,7 @@
/* eslint-disable no-var */
import 'core-js/fn/array/includes';
import 'core-js/fn/array/find';
import 'core-js/fn/object/assign';
import 'core-js/fn/object/values';
import 'core-js/fn/string/starts-with';
import 'es6-promise/auto';

View File

@ -5,6 +5,8 @@ import { swal } from '@/js/notify';
jest.mock('@/js/notify');
window.__bs_data__ = { player: false };
test('click to refresh captcha', () => {
jest.spyOn(Date, 'now');
const wrapper = mount(Register);
@ -12,6 +14,16 @@ test('click to refresh captcha', () => {
expect(Date.now).toHaveBeenCalledTimes(2);
});
test('require player name', () => {
window.__bs_data__ = { player: true };
const wrapper = mount(Register);
expect(wrapper.findAll('[type="text"]').at(0).attributes())
.toHaveProperty('placeholder', 'auth.player-name');
window.__bs_data__ = { player: false };
});
test('register', async () => {
jest.spyOn(Date, 'now');
Vue.prototype.$http.post
@ -81,3 +93,32 @@ test('register', async () => {
jest.runAllTimers();
expect(swal).toBeCalledWith({ type: 'success', text: 'ok' });
});
test('register with player name', async () => {
window.__bs_data__ = { player: true };
Vue.prototype.$http.post.mockResolvedValue({ errno: 0, msg: 'ok' });
const wrapper = mount(Register);
const button = wrapper.find('button');
const info = wrapper.find('.callout-info');
wrapper.find('[type="email"]').setValue('a@b.c');
wrapper.findAll('[type="password"]').at(0).setValue('12345678');
wrapper.findAll('[type="password"]').at(1).setValue('12345678');
wrapper.findAll('[type="text"]').at(1).setValue('captcha');
button.trigger('click');
expect(Vue.prototype.$http.post).not.toBeCalled();
expect(info.text()).toBe('auth.emptyPlayerName');
wrapper.findAll('[type="text"]').at(0).setValue('abc');
button.trigger('click');
await wrapper.vm.$nextTick();
expect(Vue.prototype.$http.post).toBeCalledWith(
'/auth/register',
{
email: 'a@b.c',
password: '12345678',
player_name: 'abc',
captcha: 'captcha'
}
);
});

View File

@ -11,6 +11,7 @@ auth:
emptyConfirmPwd: Empty confirming password.
invalidConfirmPwd: Confirming password is not equal with password.
emptyNickname: Empty nickname.
emptyPlayerName: Empty player name.
register: Register
registering: Registering
send: Send
@ -18,6 +19,7 @@ auth:
reset: Reset
resetting: Resetting
nickname: Nickname
player-name: Minecraft player name
email: Email
identification: Email or player name
password: Password
@ -28,6 +30,7 @@ auth:
keep: Remember me
repeat-pwd: Repeat your password
nickname-intro: Whatever you like expect special characters
player-name-intro: Player name in Minecraft, can be changed later
register-button: Register
forgot:
login-link: I do remember it

View File

@ -75,6 +75,9 @@ general:
user_can_register:
title: Open Registration
label: Everyone is allowed to register.
register_with_player_name:
title: Register with Player Name
label: Require Minecraft's player name when user register
require_verification:
title: Account Verification
label: Users must verify their email address first.

View File

@ -11,6 +11,7 @@ auth:
emptyConfirmPwd: 确认密码不能为空
invalidConfirmPwd: 密码和确认的密码不一样诶?
emptyNickname: 你还没有填写昵称哦
emptyPlayerName: 你还没有填写角色名哦
register: 注册
registering: 注册中
send: 发送
@ -19,6 +20,7 @@ auth:
resetting: 重置中
nickname: 昵称
email: Email
player-name: 游戏内角色名
identification: Email 或角色名
password: 密码
captcha: 请输入验证码
@ -28,6 +30,7 @@ auth:
keep: 记住我
repeat-pwd: 重复密码
nickname-intro: 昵称可使用汉字,不可包含特殊字符
player-name-intro: 游戏内的角色名,注册后可修改
register-button: 注册
forgot:
login-link: 我又想起来了

View File

@ -75,6 +75,9 @@ general:
user_can_register:
title: 开放注册
label: 任何人都可以注册
register_with_player_name:
title: 使用角色名注册
label: 注册时要求填写游戏内角色名
require_verification:
title: 邮箱验证
label: 用户必须验证邮箱后才能使用皮肤托管等功能

View File

@ -18,4 +18,14 @@
</div>
<!-- /.register-box -->
<script>
Object.defineProperty(window, '__bs_data__', {
get: function () {
return Object.freeze({
player: {{ option('register_with_player_name') ? 'true' : 'false' }},
})
},
configurable: false
})
</script>
@endsection

View File

@ -247,19 +247,82 @@ class AuthControllerTest extends TestCase
[
'email' => 'a@b.c',
'password' => str_random(33)
],
['X-Requested-With' => 'XMLHttpRequest']
]
)->assertJson([
'errno' => 1,
'msg' => trans('validation.max.string', ['attribute' => 'password', 'max' => 32])
]);
// The register_with_player_name option is set to true by default.
// Should return a warning if `player_name` is empty
$this->postJson(
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'captcha' => 'a'
]
)->assertJson([
'errno' => 1,
'msg' => trans('validation.required', ['attribute' => 'Player Name'])
]);
// Should return a warning if `player_name` is invalid
option(['player_name_rule' => 'official']);
$this->postJson(
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'player_name' => '角色名',
'captcha' => 'a'
]
)->assertJson([
'errno' => 1,
'msg' => trans('validation.player_name', ['attribute' => 'Player Name'])
]);
// Should return a warning if `player_name` is too long
$this->postJson(
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'player_name' => str_random(option('player_name_length_max') + 10),
'captcha' => 'a'
]
)->assertJson([
'errno' => 1,
'msg' => trans('validation.max.string', [
'attribute' => 'Player Name',
'max' => option('player_name_length_max')
])
]);
// Existed player
$player = factory(Player::class)->create();
$this->postJson(
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'player_name' => $player->player_name,
'captcha' => 'a'
]
)->assertJson([
'errno' => 2,
'msg' => trans('user.player.add.repeated')
]);
option(['register_with_player_name' => false]);
// Should return a warning if `nickname` is empty
$this->postJson(
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678'
'password' => '12345678',
'captcha' => 'a'
],
['X-Requested-With' => 'XMLHttpRequest']
)->assertJson([
@ -273,7 +336,8 @@ class AuthControllerTest extends TestCase
[
'email' => 'a@b.c',
'password' => '12345678',
'nickname' => '\\'
'nickname' => '\\',
'captcha' => 'a'
],
['X-Requested-With' => 'XMLHttpRequest']
)->assertJson([
@ -287,7 +351,8 @@ class AuthControllerTest extends TestCase
[
'email' => 'a@b.c',
'password' => '12345678',
'nickname' => str_random(256)
'nickname' => str_random(256),
'captcha' => 'a'
],
['X-Requested-With' => 'XMLHttpRequest']
)->assertJson([
@ -370,6 +435,19 @@ class AuthControllerTest extends TestCase
'permission' => User::NORMAL
]);
$this->assertAuthenticated();
// Require player name
option(['register_with_player_name' => false]);
$this->postJson(
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'player_name' => 'name',
'captcha' => 'a'
]
);
$this->assertNotNull(Player::where('player_name', 'name'));
}
public function testForgot()