Notifications
This commit is contained in:
parent
3d88d56a9d
commit
7a7cc2ddd9
|
|
@ -4,8 +4,10 @@ namespace App\Http\Controllers;
|
|||
|
||||
use Cache;
|
||||
use Option;
|
||||
use Notification;
|
||||
use Carbon\Carbon;
|
||||
use App\Models\User;
|
||||
use App\Notifications;
|
||||
use App\Models\Player;
|
||||
use App\Models\Texture;
|
||||
use Illuminate\Support\Str;
|
||||
|
|
@ -68,6 +70,38 @@ class AdminController extends Controller
|
|||
];
|
||||
}
|
||||
|
||||
public function sendNotification(Request $request)
|
||||
{
|
||||
$data = $this->validate($request, [
|
||||
'receiver' => 'required|in:all,normal,uid,email',
|
||||
'uid' => 'required_if:receiver,uid|nullable|integer|exists:users',
|
||||
'email' => 'required_if:receiver,email|nullable|email|exists:users',
|
||||
'title' => 'required|max:20',
|
||||
'content' => 'string|nullable',
|
||||
]);
|
||||
|
||||
$notification = new Notifications\SiteMessage($data['title'], $data['content']);
|
||||
|
||||
switch ($data['receiver']) {
|
||||
case 'all':
|
||||
$users = User::all();
|
||||
break;
|
||||
case 'normal':
|
||||
$users = User::where('permission', User::NORMAL)->get();
|
||||
break;
|
||||
case 'uid':
|
||||
$users = User::where('uid', $data['uid'])->get();
|
||||
break;
|
||||
case 'email':
|
||||
$users = User::where('email', $data['email'])->get();
|
||||
break;
|
||||
}
|
||||
Notification::send($users, $notification);
|
||||
|
||||
session(['sentResult' => trans('admin.notifications.send.success')]);
|
||||
return redirect('/admin');
|
||||
}
|
||||
|
||||
public function customize(Request $request)
|
||||
{
|
||||
$homepage = Option::form('homepage', OptionForm::AUTO_DETECT, function ($form) {
|
||||
|
|
|
|||
|
|
@ -301,5 +301,20 @@ class UserController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
// @codeCoverageIgnore
|
||||
public function readNotification($id)
|
||||
{
|
||||
$notification = auth()
|
||||
->user()
|
||||
->unreadNotifications
|
||||
->first(function ($notification) use ($id) {
|
||||
return $notification->id === $id;
|
||||
});
|
||||
$notification->markAsRead();
|
||||
|
||||
return [
|
||||
'title' => $notification->data['title'],
|
||||
'content' => app('parsedown')->text($notification->data['content']),
|
||||
'time' => $notification->created_at->toDateTimeString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@ use Illuminate\Support\Arr;
|
|||
use Laravel\Passport\HasApiTokens;
|
||||
use App\Events\EncryptUserPassword;
|
||||
use Tymon\JWTAuth\Contracts\JWTSubject;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
|
||||
class User extends Authenticatable implements JWTSubject
|
||||
{
|
||||
use Notifiable;
|
||||
use HasApiTokens;
|
||||
|
||||
/**
|
||||
|
|
|
|||
50
app/Notifications/SiteMessage.php
Normal file
50
app/Notifications/SiteMessage.php
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class SiteMessage extends Notification
|
||||
{
|
||||
public $title;
|
||||
|
||||
public $content;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(string $title, $content = '')
|
||||
{
|
||||
$this->title = $title;
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['database'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
'title' => $this->title,
|
||||
'content' => $this->content,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,8 @@ namespace App\Services;
|
|||
use Event;
|
||||
use Closure;
|
||||
use App\Events;
|
||||
use Notification;
|
||||
use App\Notifications;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Hook
|
||||
|
|
@ -126,4 +128,9 @@ class Hook
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static function sendNotification($users, string $title, $content = ''): void
|
||||
{
|
||||
Notification::send($users, new Notifications\SiteMessage($title, $content));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,6 +160,7 @@ return [
|
|||
Illuminate\Foundation\Providers\FoundationServiceProvider::class,
|
||||
Illuminate\Hashing\HashServiceProvider::class,
|
||||
Illuminate\Mail\MailServiceProvider::class,
|
||||
Illuminate\Notifications\NotificationServiceProvider::class,
|
||||
Illuminate\Pagination\PaginationServiceProvider::class,
|
||||
Illuminate\Pipeline\PipelineServiceProvider::class,
|
||||
Illuminate\Queue\QueueServiceProvider::class,
|
||||
|
|
@ -217,6 +218,7 @@ return [
|
|||
'Lang' => Illuminate\Support\Facades\Lang::class,
|
||||
'Log' => Illuminate\Support\Facades\Log::class,
|
||||
'Mail' => Illuminate\Support\Facades\Mail::class,
|
||||
'Notification' => Illuminate\Support\Facades\Notification::class,
|
||||
'Password' => Illuminate\Support\Facades\Password::class,
|
||||
'Queue' => Illuminate\Support\Facades\Queue::class,
|
||||
'Redirect' => Illuminate\Support\Facades\Redirect::class,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateNotificationsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('notifications', function (Blueprint $table) {
|
||||
$table->uuid('id')->primary();
|
||||
$table->string('type');
|
||||
$table->morphs('notifiable');
|
||||
$table->text('data');
|
||||
$table->timestamp('read_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('notifications');
|
||||
}
|
||||
}
|
||||
7
database/update_scripts/update-4.2.1-to-4.3.0.php
Normal file
7
database/update_scripts/update-4.2.1-to-4.3.0.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'请您手动打开终端或 PowerShell 执行以下命令以完成升级:',
|
||||
'Please open terminal or PowerShell to complete upgrade:',
|
||||
'<code>php artisan migrate --force</code>',
|
||||
];
|
||||
|
|
@ -11,5 +11,6 @@ import 'admin-lte/build/js/Tree'
|
|||
import './i18n'
|
||||
import './net'
|
||||
import './event'
|
||||
import './notification'
|
||||
import './element'
|
||||
import './logout'
|
||||
|
|
|
|||
25
resources/assets/src/scripts/notification.ts
Normal file
25
resources/assets/src/scripts/notification.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { get } from './net'
|
||||
import { showModal } from './notify'
|
||||
|
||||
export default async function handler(event: Event) {
|
||||
const item = event.target as HTMLAnchorElement
|
||||
const id = item.getAttribute('data-nid')
|
||||
const {
|
||||
title, content, time,
|
||||
} = await get(`/user/notifications/${id}`)
|
||||
showModal(`${content}<br><small>${time}</small>`, title)
|
||||
item.remove()
|
||||
const counter = document.querySelector('.notifications-counter') as HTMLSpanElement
|
||||
const value = Number.parseInt(counter.textContent!) - 1
|
||||
if (value > 0) {
|
||||
counter.textContent = value.toString()
|
||||
} else {
|
||||
counter.remove()
|
||||
}
|
||||
}
|
||||
|
||||
const el = document.querySelector('.notifications-list')
|
||||
// istanbul ignore next
|
||||
if (el) {
|
||||
el.addEventListener('click', handler)
|
||||
}
|
||||
34
resources/assets/tests/scripts/notification.test.ts
Normal file
34
resources/assets/tests/scripts/notification.test.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { get } from '@/scripts/net'
|
||||
import { showModal } from '@/scripts/notify'
|
||||
import { flushPromises } from '../utils'
|
||||
import handler from '@/scripts/notification'
|
||||
|
||||
jest.mock('@/scripts/net')
|
||||
jest.mock('@/scripts/notify')
|
||||
|
||||
test('read notification', async () => {
|
||||
document.body.innerHTML = `
|
||||
<div class="notifications-list">
|
||||
<span class="notifications-counter">2</span>
|
||||
<a data-nid="1"></a>
|
||||
<a data-nid="2"></a>
|
||||
</div>
|
||||
`
|
||||
document.querySelector('.notifications-list')!.addEventListener('click', handler)
|
||||
get.mockResolvedValue({
|
||||
title: 'title',
|
||||
content: 'content',
|
||||
time: 'time',
|
||||
})
|
||||
|
||||
document.querySelector('a')!.click()
|
||||
await flushPromises()
|
||||
expect(get).toBeCalledWith('/user/notifications/1')
|
||||
expect(showModal).toBeCalledWith('content<br><small>time</small>', 'title')
|
||||
expect(document.querySelectorAll('a')).toHaveLength(1)
|
||||
expect(document.querySelector('span')!.textContent).toBe('1')
|
||||
|
||||
document.querySelector('a')!.click()
|
||||
await flushPromises()
|
||||
expect(document.querySelector('span')).toBeNull()
|
||||
})
|
||||
|
|
@ -7,6 +7,19 @@ index:
|
|||
texture-uploads: Texture Uploads
|
||||
user-registration: User Registration
|
||||
|
||||
notifications:
|
||||
send:
|
||||
title: Send Notification
|
||||
success: Sent successfully!
|
||||
receiver:
|
||||
title: Receiver
|
||||
all: All Users
|
||||
normal: Normal Users
|
||||
uid: Specified UID
|
||||
email: Specified Email
|
||||
title: Title
|
||||
content: Content (Markdown is supported.)
|
||||
|
||||
users:
|
||||
status:
|
||||
normal: Normal
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ cant-sign-until: You can't sign in in :time :unit
|
|||
last-sign: Last signed at :time
|
||||
sign-remain-time: Available after :time :unit
|
||||
announcement: Announcement
|
||||
no-unread: No new notifications.
|
||||
|
||||
verification:
|
||||
disabled: Email verification is not available.
|
||||
|
|
|
|||
|
|
@ -7,6 +7,19 @@ index:
|
|||
texture-uploads: 材质上传
|
||||
user-registration: 用户注册
|
||||
|
||||
notifications:
|
||||
send:
|
||||
title: 发送通知
|
||||
success: 发送成功
|
||||
receiver:
|
||||
title: 通知对象
|
||||
all: 所有用户
|
||||
normal: 普通用户
|
||||
uid: 指定 UID
|
||||
email: 指定邮箱
|
||||
title: 标题
|
||||
content: 内容(可使用 Markdown)
|
||||
|
||||
users:
|
||||
status:
|
||||
normal: 普通用户
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ cant-sign-until: :time :unit 后才能再次签到哦
|
|||
last-sign: 上次签到于 :time
|
||||
sign-remain-time: :time :unit 后可签到
|
||||
announcement: 公告
|
||||
no-unread: 无未读通知
|
||||
|
||||
|
||||
verification:
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
- Custom `PLUGINS_DIR` with relative path is allowed.
|
||||
- Added link for editing announcement.
|
||||
- New plugin API: [`Hook::addUserBadge`](https://bs-plugin.netlify.com/guide/bootstrap.html#%E6%98%BE%E7%A4%BA%E7%94%A8%E6%88%B7-badge).
|
||||
- New feature: Notifications.
|
||||
- New plugin API: [`Hook::sendNotification`](https://bs-plugin.netlify.com/guide/bootstrap.html#%E5%8F%91%E9%80%81%E9%80%9A%E7%9F%A5)
|
||||
|
||||
## Tweaked
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
- 允许在 `PLUGINS_DIR` 配置项中使用相对路径
|
||||
- 添加「编辑公告」的链接
|
||||
- 新插件 API:[`Hook::addUserBadge`](https://bs-plugin.netlify.com/guide/bootstrap.html#%E6%98%BE%E7%A4%BA%E7%94%A8%E6%88%B7-badge)
|
||||
- 新功能:发送通知。
|
||||
- 新插件 API:[`Hook::sendNotification`](https://bs-plugin.netlify.com/guide/bootstrap.html#%E5%8F%91%E9%80%81%E9%80%9A%E7%9F%A5)
|
||||
|
||||
## 调整
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,63 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">@lang('admin.notifications.send.title')</h3>
|
||||
</div>
|
||||
<form method="post" action="{{ url('/admin/notifications/send') }}">
|
||||
@csrf
|
||||
<div class="box-body">
|
||||
@if ($errors->any())
|
||||
<div class="callout callout-danger">{{ $errors->first() }}</div>
|
||||
@endif
|
||||
@if ($sentResult = Session::pull('sentResult'))
|
||||
<div class="callout callout-success">{{ $sentResult }}</div>
|
||||
@endif
|
||||
<div class="form-group">
|
||||
<label>@lang('admin.notifications.receiver.title')</label>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="receiver" value="all" required>
|
||||
@lang('admin.notifications.receiver.all')
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="receiver" value="normal" required>
|
||||
@lang('admin.notifications.receiver.normal')
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="receiver" value="uid" required>
|
||||
@lang('admin.notifications.receiver.uid')
|
||||
<input type="number" name="uid" class="form-control">
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="receiver" value="email" required>
|
||||
@lang('admin.notifications.receiver.email')
|
||||
<input type="email" name="email" class="form-control">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>@lang('admin.notifications.title')</label>
|
||||
<input type="text" name="title" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>@lang('admin.notifications.content')</label>
|
||||
<textarea name="content" class="form-control" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<input type="submit" value="@lang('general.submit')" class="el-button el-button--primary">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
|
|
@ -78,8 +135,8 @@
|
|||
</div>
|
||||
<div class="box-body">
|
||||
<div id="chart"></div>
|
||||
</div><!-- /.box-body -->
|
||||
</div><!-- /.box -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@
|
|||
<!-- Navbar Right Menu -->
|
||||
<div class="navbar-custom-menu">
|
||||
<ul class="nav navbar-nav">
|
||||
@include('common.notifications-menu')
|
||||
|
||||
@include('common.language')
|
||||
|
||||
@include('common.user-menu')
|
||||
|
|
|
|||
30
resources/views/common/notifications-menu.blade.php
Normal file
30
resources/views/common/notifications-menu.blade.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
@php
|
||||
$notifications = $user->unreadNotifications;
|
||||
$count = $notifications->count();
|
||||
@endphp
|
||||
|
||||
<li class="dropdown notifications-menu">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="fas fa-bell"></i>
|
||||
@if ($count > 0)
|
||||
<span class="label label-warning notifications-counter">{{ $count }}</span>
|
||||
@endif
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
@if ($count === 0)
|
||||
<li class="header text-center">@lang('user.no-unread')</li>
|
||||
@else
|
||||
<li>
|
||||
<ul class="menu notifications-list">
|
||||
@foreach ($notifications as $notification)
|
||||
<li>
|
||||
<a href="#" data-nid="{{ $notification->id }}">
|
||||
<i class="far fa-circle text-aqua"></i> {{ $notification->data['title'] }}
|
||||
</a>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</li>
|
||||
@endif
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -37,15 +37,20 @@
|
|||
<li class="active">
|
||||
<a href="{{ url('skinlib') }}">@lang('general.skinlib')</a>
|
||||
</li>
|
||||
@auth
|
||||
<li>
|
||||
<a href="{{ url('user/closet') }}">@lang('general.my-closet')</a>
|
||||
</li>
|
||||
@endauth
|
||||
</ul>
|
||||
</div><!-- /.navbar-collapse -->
|
||||
<!-- Navbar Right Menu -->
|
||||
<div class="navbar-custom-menu">
|
||||
<ul class="nav navbar-nav">
|
||||
@auth
|
||||
<li><a href="{{ url('skinlib/upload') }}"><i class="fas fa-upload" aria-hidden="true"></i> <span class="description-text">@lang('skinlib.general.upload-new-skin')</span></a></li>
|
||||
@include('common.notifications-menu')
|
||||
@endauth
|
||||
|
||||
@include('common.language')
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@
|
|||
<!-- Navbar Right Menu -->
|
||||
<div class="navbar-custom-menu">
|
||||
<ul class="nav navbar-nav">
|
||||
@include('common.notifications-menu')
|
||||
|
||||
@include('common.language')
|
||||
|
||||
@include('common.user-menu')
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ Route::group([
|
|||
'prefix' => 'user',
|
||||
], function () {
|
||||
Route::any('', 'UserController@index');
|
||||
Route::get('/notifications/{id}', 'UserController@readNotification');
|
||||
Route::get('/score-info', 'UserController@scoreInfo');
|
||||
Route::post('/sign', 'UserController@sign');
|
||||
|
||||
|
|
@ -115,6 +116,7 @@ Route::group(['prefix' => 'skinlib'], function () {
|
|||
Route::group(['middleware' => ['authorize', 'admin'], 'prefix' => 'admin'], function () {
|
||||
Route::view('/', 'admin.index');
|
||||
Route::get('/chart', 'AdminController@chartData');
|
||||
Route::post('/notifications/send', 'AdminController@sendNotification');
|
||||
|
||||
Route::any('/customize', 'AdminController@customize');
|
||||
Route::any('/score', 'AdminController@score');
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace Tests;
|
||||
|
||||
use Notification;
|
||||
use App\Models\User;
|
||||
use App\Notifications;
|
||||
use App\Models\Player;
|
||||
use App\Models\Texture;
|
||||
use Illuminate\Support\Str;
|
||||
|
|
@ -32,7 +34,83 @@ class AdminControllerTest extends TestCase
|
|||
->assertJsonStructure(['labels', 'xAxis', 'data']);
|
||||
}
|
||||
|
||||
public function testSendNotification()
|
||||
{
|
||||
$admin = factory(User::class, 'admin')->create();
|
||||
$normal = factory(User::class)->create();
|
||||
Notification::fake();
|
||||
|
||||
$this->actingAs($admin)
|
||||
->post('/admin/notifications/send', [
|
||||
'receiver' => 'all',
|
||||
'title' => 'all users',
|
||||
'content' => null,
|
||||
])
|
||||
->assertRedirect('/admin')
|
||||
->assertSessionHas('sentResult', trans('admin.notifications.send.success'));
|
||||
Notification::assertSentTo(
|
||||
[$admin, $normal],
|
||||
Notifications\SiteMessage::class,
|
||||
function ($notification) {
|
||||
$this->assertEquals('all users', $notification->title);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
Notification::fake();
|
||||
Notification::assertNothingSent();
|
||||
$this->post('/admin/notifications/send', [
|
||||
'receiver' => 'normal',
|
||||
'title' => 'normal only',
|
||||
'content' => 'hi',
|
||||
]);
|
||||
Notification::assertSentTo(
|
||||
$normal,
|
||||
Notifications\SiteMessage::class,
|
||||
function ($notification) {
|
||||
$this->assertEquals('normal only', $notification->title);
|
||||
$this->assertEquals('hi', $notification->content);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
Notification::assertNotSentTo($admin, Notifications\SiteMessage::class);
|
||||
|
||||
Notification::fake();
|
||||
Notification::assertNothingSent();
|
||||
$this->post('/admin/notifications/send', [
|
||||
'receiver' => 'uid',
|
||||
'title' => 'uid',
|
||||
'content' => null,
|
||||
'uid' => $normal->uid,
|
||||
]);
|
||||
Notification::assertSentTo(
|
||||
$normal,
|
||||
Notifications\SiteMessage::class,
|
||||
function ($notification) {
|
||||
$this->assertEquals('uid', $notification->title);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
Notification::assertNotSentTo($admin, Notifications\SiteMessage::class);
|
||||
|
||||
Notification::fake();
|
||||
Notification::assertNothingSent();
|
||||
$this->post('/admin/notifications/send', [
|
||||
'receiver' => 'email',
|
||||
'title' => 'email',
|
||||
'content' => null,
|
||||
'email' => $normal->email,
|
||||
]);
|
||||
Notification::assertSentTo(
|
||||
$normal,
|
||||
Notifications\SiteMessage::class,
|
||||
function ($notification) {
|
||||
$this->assertEquals('email', $notification->title);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
Notification::assertNotSentTo($admin, Notifications\SiteMessage::class);
|
||||
}
|
||||
|
||||
public function testUsers()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Tests;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\Hook;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Tests\Concerns\GeneratesFakePlugins;
|
||||
|
|
@ -92,4 +93,14 @@ class HookTest extends TestCase
|
|||
->get('/user')
|
||||
->assertSee('<small class="label bg-green">hi</small>');
|
||||
}
|
||||
|
||||
public function testSendNotification()
|
||||
{
|
||||
$user = factory(User::class)->create();
|
||||
Hook::sendNotification([$user], 'Ibara Mayaka');
|
||||
$this->actingAs($user)
|
||||
->get('/user')
|
||||
->assertSee('<span class="label label-warning">1</span>')
|
||||
->assertSee('Ibara Mayaka');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,12 @@ class SetupControllerTest extends TestCase
|
|||
'textures',
|
||||
'users',
|
||||
'reports',
|
||||
'oauth_auth_codes',
|
||||
'oauth_access_tokens',
|
||||
'oauth_clients',
|
||||
'oauth_personal_access_clients',
|
||||
'oauth_refresh_tokens',
|
||||
'notifications',
|
||||
];
|
||||
array_walk($tables, function ($table) {
|
||||
Schema::dropIfExists($table);
|
||||
|
|
@ -84,11 +90,6 @@ class SetupControllerTest extends TestCase
|
|||
public function testInfo()
|
||||
{
|
||||
$this->get('/setup/info')->assertViewIs('setup.wizard.info');
|
||||
Schema::dropIfExists('oauth_auth_codes');
|
||||
Schema::dropIfExists('oauth_access_tokens');
|
||||
Schema::dropIfExists('oauth_clients');
|
||||
Schema::dropIfExists('oauth_personal_access_clients');
|
||||
Schema::dropIfExists('oauth_refresh_tokens');
|
||||
Artisan::call('migrate:refresh');
|
||||
Schema::drop('users');
|
||||
$this->get('/setup/info')->assertSee('already exist');
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use Event;
|
|||
use Parsedown;
|
||||
use App\Events;
|
||||
use App\Models\User;
|
||||
use App\Notifications;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Mail\EmailVerification;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
|
@ -490,4 +491,22 @@ class UserControllerTest extends TestCase
|
|||
->assertJson(['code' => 0]);
|
||||
$this->assertEquals(0, User::find($user->uid)->avatar);
|
||||
}
|
||||
|
||||
public function testReadNotification()
|
||||
{
|
||||
$user = factory(User::class)->create();
|
||||
$user->notify(new Notifications\SiteMessage('Hyouka', 'Kotenbu?'));
|
||||
$user->refresh();
|
||||
$notification = $user->unreadNotifications->first();
|
||||
|
||||
$this->actingAs($user)
|
||||
->get('/user/notifications/'.$notification->id)
|
||||
->assertJson([
|
||||
'title' => $notification->data['title'],
|
||||
'content' => app('parsedown')->text($notification->data['content']),
|
||||
'time' => $notification->created_at->toDateTimeString(),
|
||||
]);
|
||||
$notification->refresh();
|
||||
$this->assertNotNull($notification->read_at);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user