diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 1fe49971..0c24bcfa 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -95,11 +95,16 @@ class UserController extends Controller ]); } - public function sign() + public function sign(Dispatcher $dispatcher, Filter $filter) { /** @var User */ $user = Auth::user(); + $can = $filter->apply('can_sign', true); + if ($can instanceof Rejection) { + return json($can->getReason(), 2); + } + $lastSignTime = Carbon::parse($user->last_sign_at); $remainingTime = option('sign_after_zero') ? Carbon::now()->diffInSeconds( @@ -114,10 +119,16 @@ class UserController extends Controller if ($remainingTime <= 0) { [$min, $max] = explode(',', option('sign_score')); $acquiredScore = rand((int) $min, (int) $max); + $acquiredScore = $filter->apply('sign_score', $acquiredScore); + + $dispatcher->dispatch('user.sign.before', [$acquiredScore]); + $user->score += $acquiredScore; $user->last_sign_at = Carbon::now(); $user->save(); + $dispatcher->dispatch('user.sign.after', [$acquiredScore]); + return json(trans('user.sign-success', ['score' => $acquiredScore]), 0, [ 'score' => $user->score, ]); diff --git a/resources/assets/src/views/user/Dashboard/index.tsx b/resources/assets/src/views/user/Dashboard/index.tsx index 11d8f2bb..9ecaa903 100644 --- a/resources/assets/src/views/user/Dashboard/index.tsx +++ b/resources/assets/src/views/user/Dashboard/index.tsx @@ -82,13 +82,15 @@ const Dashboard: React.FC = () => { setLastSign(new Date()) setTweenedScore(data.score) setScore(data.score) - } else { + } else if (code === 1) { const remainingTime = scoreUtils.remainingTime( lastSign, signGap, canSignAfterZero, ) toast.warning(scoreUtils.remainingTimeText(remainingTime)) + } else { + toast.error(message) } setLoading(false) }, []) diff --git a/resources/assets/tests/views/user/Dashboard.test.tsx b/resources/assets/tests/views/user/Dashboard.test.tsx index 202bf3af..50952204 100644 --- a/resources/assets/tests/views/user/Dashboard.test.tsx +++ b/resources/assets/tests/views/user/Dashboard.test.tsx @@ -87,7 +87,7 @@ describe('sign', () => { expect(queryByText(/905/)).toBeInTheDocument() }) - it('failed', async () => { + it('cannot sign', async () => { fetch.post.mockResolvedValue({ code: 1, message: '' }) const { getByRole, getByText } = render() @@ -102,6 +102,19 @@ describe('sign', () => { ).toBeInTheDocument() expect(getByRole('alert')).toHaveClass('alert-warning') }) + + it('failed', async () => { + fetch.post.mockResolvedValue({ code: 2, message: 'f' }) + + const { getByRole, getByText } = render() + await waitFor(() => expect(fetch.get).toBeCalledTimes(1)) + + fireEvent.click(getByRole('button')) + await waitFor(() => expect(fetch.post).toBeCalledWith(urls.user.sign())) + + expect(getByText('f')).toBeInTheDocument() + expect(getByRole('alert')).toHaveClass('alert-danger') + }) }) describe('sign button', () => { diff --git a/tests/HttpTest/ControllersTest/UserControllerTest.php b/tests/HttpTest/ControllersTest/UserControllerTest.php index fed56e96..4e077df5 100644 --- a/tests/HttpTest/ControllersTest/UserControllerTest.php +++ b/tests/HttpTest/ControllersTest/UserControllerTest.php @@ -79,6 +79,8 @@ class UserControllerTest extends TestCase public function testSign() { + Event::fake(); + $filter = Fakes\Filter::fake(); option(['sign_score' => '50,50']); $user = factory(User::class)->create(); @@ -92,25 +94,59 @@ class UserControllerTest extends TestCase 'score' => option('user_initial_score') + 50, ], ]); + $filter->assertApplied('sign_score', function ($score) { + $this->assertEquals(50, $score); + + return true; + }); + Event::assertDispatched('user.sign.before', function ($eventName, $payload) { + $this->assertEquals(50, $payload[0]); + + return true; + }); + Event::assertDispatched('user.sign.after', function ($eventName, $payload) { + $this->assertEquals(50, $payload[0]); + + return true; + }); // remaining time is greater than 0 + Event::fake(); $user = factory(User::class)->create(['last_sign_at' => Carbon::now()]); option(['sign_gap_time' => 2]); $this->actingAs($user) ->postJson('/user/sign') ->assertJson(['code' => 1]); + Event::assertNotDispatched('user.sign.before'); + Event::assertNotDispatched('user.sign.after'); // can sign after 0 o'clock + Event::fake(); option(['sign_after_zero' => true]); $user = factory(User::class)->create(['last_sign_at' => Carbon::now()]); $this->actingAs($user) ->postJson('/user/sign') ->assertJson(['code' => 1]); + Event::assertNotDispatched('user.sign.before'); + Event::assertNotDispatched('user.sign.after'); $user = factory(User::class)->create([ 'last_sign_at' => Carbon::today(), ]); - $this->actingAs($user)->postJson('/user/sign')->assertJson(['code' => 0]); + $this->actingAs($user) + ->postJson('/user/sign') + ->assertJson(['code' => 0]); + + // rejected + Event::fake(); + $filter->add('can_sign', function () { + return new Rejection('rejected'); + }); + $this + ->postJson('/user/sign') + ->assertJson(['code' => 2, 'message' => 'rejected']); + Event::assertNotDispatched('user.sign.before'); + Event::assertNotDispatched('user.sign.after'); } public function testSendVerificationEmail()