optimize querying reports

This commit is contained in:
Pig Fang 2020-06-08 09:51:35 +08:00
parent 322b1a4c5e
commit 2fb67537df
5 changed files with 46 additions and 24 deletions

View File

@ -20,6 +20,7 @@ class ReportController extends Controller
'tid' => 'required|exists:textures', 'tid' => 'required|exists:textures',
'reason' => 'required', 'reason' => 'required',
]); ]);
/** @var User */
$reporter = auth()->user(); $reporter = auth()->user();
$tid = $data['tid']; $tid = $data['tid'];
$reason = $data['reason']; $reason = $data['reason'];
@ -68,22 +69,9 @@ class ReportController extends Controller
{ {
$q = $request->input('q'); $q = $request->input('q');
$pagination = Report::usingSearchString($q)->paginate(9); return Report::usingSearchString($q)
$collection = $pagination->getCollection()->map(function ($report) { ->with(['texture', 'textureUploader', 'informer'])
$uploader = User::find($report->uploader); ->paginate(9);
if ($uploader) {
$report->uploaderName = $uploader->nickname;
}
if ($report->informer) {
$report->reporterName = $report->informer->nickname;
}
$report->getAttribute('texture');
return $report;
});
$pagination->setCollection($collection);
return $pagination;
} }
public function review( public function review(

View File

@ -51,6 +51,11 @@ class Report extends Model
return $this->belongsTo(Texture::class, 'tid', 'tid'); return $this->belongsTo(Texture::class, 'tid', 'tid');
} }
public function textureUploader()
{
return $this->belongsTo(User::class, 'uploader', 'uid');
}
public function informer() public function informer()
{ {
return $this->belongsTo(User::class, 'reporter', 'uid'); return $this->belongsTo(User::class, 'reporter', 'uid');

View File

@ -49,7 +49,7 @@ const ImageBox: React.FC<Props> = (props) => {
{t('skinlib.show.uploader')} {t('skinlib.show.uploader')}
{': '} {': '}
</b> </b>
<span className="mr-1">{report.uploaderName}</span> <span className="mr-1">{report.texture_uploader?.nickname}</span>
(UID: {report.uploader}) (UID: {report.uploader})
</div> </div>
<div className="card-body"> <div className="card-body">
@ -114,7 +114,7 @@ const ImageBox: React.FC<Props> = (props) => {
{t('report.reporter')} {t('report.reporter')}
{': '} {': '}
</b> </b>
<span className="mr-1">{report.reporterName}</span> <span className="mr-1">{report.informer?.nickname}</span>
(UID: {report.reporter}) (UID: {report.reporter})
</div> </div>
<details> <details>

View File

@ -1,4 +1,4 @@
import { Texture } from '@/scripts/types' import { Texture, User } from '@/scripts/types'
export const enum Status { export const enum Status {
Pending = 0, Pending = 0,
@ -11,9 +11,9 @@ export type Report = {
tid: number tid: number
texture: Texture | null texture: Texture | null
uploader: number uploader: number
uploaderName: string texture_uploader: User | null
reporter: number reporter: number
reporterName: string informer: User | null
reason: string reason: string
status: Status status: Status
report_at: string report_at: string

View File

@ -3,7 +3,7 @@ import { render, waitFor, fireEvent } from '@testing-library/react'
import { createPaginator } from '../../utils' import { createPaginator } from '../../utils'
import { t } from '@/scripts/i18n' import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net' import * as fetch from '@/scripts/net'
import { Texture, TextureType } from '@/scripts/types' import { Texture, TextureType, User, UserPermission } from '@/scripts/types'
import ReportsManagement from '@/views/admin/ReportsManagement' import ReportsManagement from '@/views/admin/ReportsManagement'
import { Report, Status } from '@/views/admin/ReportsManagement/types' import { Report, Status } from '@/views/admin/ReportsManagement/types'
@ -14,9 +14,31 @@ const fixture: Readonly<Report> = Object.freeze<Report>({
tid: 1, tid: 1,
texture: null, texture: null,
uploader: 1, uploader: 1,
uploaderName: 'xx', texture_uploader: Object.freeze<Readonly<User>>({
uid: 1,
email: 'a@b.c',
nickname: 'abc',
score: 1000,
avatar: 0,
permission: UserPermission.Normal,
ip: '::1',
last_sign_at: new Date().toString(),
register_at: new Date().toString(),
verified: true,
}),
reporter: 2, reporter: 2,
reporterName: 'yy', informer: Object.freeze<Readonly<User>>({
uid: 1,
email: 'a@b.c',
nickname: 'abc',
score: 1000,
avatar: 0,
permission: UserPermission.Normal,
ip: '::1',
last_sign_at: new Date().toString(),
register_at: new Date().toString(),
verified: true,
}),
reason: 'nsfw', reason: 'nsfw',
status: Status.Pending, status: Status.Pending,
report_at: new Date().toString(), report_at: new Date().toString(),
@ -45,6 +67,13 @@ test('search reports', async () => {
) )
}) })
test('empty reporter or texture uploader', async () => {
const report = { ...fixture, texture_uploader: null, informer: null }
fetch.get.mockResolvedValue(createPaginator([report]))
render(<ReportsManagement />)
})
test('preview texture', async () => { test('preview texture', async () => {
const texture: Texture = { const texture: Texture = {
tid: fixture.tid, tid: fixture.tid,