优化代码

main
gzydong 2021-06-30 19:27:49 +08:00
parent 4481ba558a
commit 4590728cb1
13 changed files with 147 additions and 206 deletions

View File

@ -24,6 +24,7 @@ use App\Model\Group\GroupMember;
use App\Service\TalkService;
use Hyperf\Command\Command as HyperfCommand;
use Hyperf\Command\Annotation\Command;
use League\Flysystem\Filesystem;
use Psr\Container\ContainerInterface;
/**
@ -173,5 +174,7 @@ class TestCommand extends HyperfCommand
//var_dump(FriendRemark::getInstance());
//var_dump(Group::isManager(2054,116));
var_dump(pathinfo('spring-boot相关',PATHINFO_EXTENSION));
}
}

View File

@ -16,8 +16,7 @@ use Hyperf\HttpServer\Annotation\RequestMapping;
use Hyperf\HttpServer\Annotation\Middleware;
use App\Middleware\JWTAuthMiddleware;
use App\Service\ArticleService;
use App\Service\UploadService;
use Hyperf\Utils\Str;
use League\Flysystem\Filesystem;
use Psr\Http\Message\ResponseInterface;
use App\Cache\Repository\LockRedis;
@ -36,12 +35,6 @@ class ArticleController extends CController
*/
private $articleService;
/**
* @inject
* @var UploadService
*/
private $uploadService;
/**
* 获取笔记分类列表
* @RequestMapping(path="article-class", methods="get")
@ -180,7 +173,6 @@ class ArticleController extends CController
$lockKey = "article:sort_{$params['class_id']}_{$params['sort_type']}";
// 获取Redis锁
$lock = LockRedis::getInstance();
if ($lock->lock($lockKey, 3, 500)) {
$isTrue = $this->articleService->articleClassSort($this->uid(), (int)$params['class_id'], (int)$params['sort_type']);
@ -332,9 +324,10 @@ class ArticleController extends CController
* 笔记图片上传接口
* @RequestMapping(path="upload-article-image", methods="post")
*
* @param Filesystem $filesystem
* @return ResponseInterface
*/
public function uploadArticleImage()
public function uploadArticleImage(Filesystem $filesystem)
{
$file = $this->request->file('image');
if (!$file || !$file->isValid()) {
@ -346,10 +339,10 @@ class ArticleController extends CController
return $this->response->fail('图片格式错误目前仅支持jpg、png、jpeg、gif和webp');
}
$imgInfo = getimagesize($file->getRealPath());
$path = $this->uploadService->media($file, 'media/images/notes/', create_image_name($ext, $imgInfo[0], $imgInfo[1]));
if (!$path) {
try {
$path = 'media/images/notes/' . date('Ymd') . '/' . create_image_name($ext, getimagesize($file->getRealPath()));
$filesystem->write($path, file_get_contents($file->getRealPath()));
} catch (\Exception $e) {
return $this->response->fail();
}
@ -456,7 +449,7 @@ class ArticleController extends CController
*
* @return ResponseInterface
*/
public function uploadArticleAnnex()
public function uploadArticleAnnex(Filesystem $filesystem)
{
$params = $this->request->inputs(['article_id']);
$this->validate($params, [
@ -469,23 +462,22 @@ class ArticleController extends CController
}
$annex = [
'file_suffix' => $file->getExtension(),
'file_suffix' => pathinfo($file->getClientFilename(), PATHINFO_EXTENSION),
'file_size' => $file->getSize(),
'save_dir' => '',
'original_name' => $file->getClientFilename()
];
$path = $this->uploadService->media($file,
'files/notes/' . date('Ymd'),
"[{$annex['file_suffix']}]" . uniqid() . Str::random(16) . '.' . 'tmp'
);
if (!$path) {
try {
$path = 'files/notes/' . date('Ymd') . '/' . "[{$annex['file_suffix']}]" . create_random_filename('tmp');
$filesystem->write($path, file_get_contents($file->getRealPath()));
} catch (\Exception $e) {
return $this->response->fail();
}
$annex['save_dir'] = $path;
$annex['id'] = $this->articleService->insertArticleAnnex($this->uid(), (int)$params['article_id'], $annex);
if (!$annex['id']) {
return $this->response->fail('附件上传失败,请稍后再试!');
}

View File

@ -19,8 +19,8 @@ use App\Model\Article\ArticleAnnex;
use App\Model\Chat\ChatRecord;
use App\Model\Chat\ChatRecordsFile;
use App\Model\Group\Group;
use App\Service\UploadService;
use Hyperf\HttpServer\Contract\ResponseInterface;
use League\Flysystem\Filesystem;
/**
* Class DownloadController
@ -31,15 +31,20 @@ use Hyperf\HttpServer\Contract\ResponseInterface;
*/
class DownloadController extends CController
{
private function getFilePath(string $path)
{
return container()->get(Filesystem::class)->getConfig()->get('root') . '/' . $path;
}
/**
* 下载用户聊天文件
* @RequestMapping(path="user-chat-file", methods="get")
*
* @param ResponseInterface $response
* @param UploadService $uploadService
* @param Filesystem $filesystem
* @return \Psr\Http\Message\ResponseInterface
*/
public function userChatFile(ResponseInterface $response, UploadService $uploadService)
public function userChatFile(ResponseInterface $response, Filesystem $filesystem)
{
$params = $this->request->inputs(['cr_id']);
$this->validate($params, [
@ -66,12 +71,12 @@ class DownloadController extends CController
}
}
$fileInfo = ChatRecordsFile::select(['save_dir', 'original_name'])->where('record_id', $params['cr_id'])->first();
if (!$fileInfo || !file_exists($uploadService->driver($fileInfo->save_dir))) {
$info = ChatRecordsFile::select(['save_dir', 'original_name'])->where('record_id', $params['cr_id'])->first();
if (!$info || !$filesystem->has($info->save_dir)) {
return $this->response->fail('文件不存在或没有下载权限!');
}
return $response->download($uploadService->driver($fileInfo->save_dir), $fileInfo->original_name);
return $response->download($this->getFilePath($info->save_dir), $info->original_name);
}
/**
@ -79,10 +84,10 @@ class DownloadController extends CController
* @RequestMapping(path="article-annex", methods="get")
*
* @param ResponseInterface $response
* @param UploadService $uploadService
* @param Filesystem $filesystem
* @return \Psr\Http\Message\ResponseInterface
*/
public function articleAnnex(ResponseInterface $response, UploadService $uploadService)
public function articleAnnex(ResponseInterface $response, Filesystem $filesystem)
{
$params = $this->request->inputs(['annex_id']);
$this->validate($params, [
@ -94,10 +99,10 @@ class DownloadController extends CController
->where('user_id', $this->uid())
->first();
if (!$info || !file_exists($uploadService->driver($info->save_dir))) {
if (!$info || !$filesystem->has($info->save_dir)) {
return $this->response->fail('文件不存在或没有下载权限!');
}
return $response->download($uploadService->driver($info->save_dir), $info->original_name);
return $response->download($this->getFilePath($info->save_dir), $info->original_name);
}
}

View File

@ -19,7 +19,7 @@ use App\Constants\ResponseCode;
use App\Model\Emoticon;
use App\Model\EmoticonDetail;
use App\Service\EmoticonService;
use App\Service\UploadService;
use League\Flysystem\Filesystem;
use Psr\Http\Message\ResponseInterface;
/**
@ -143,10 +143,10 @@ class EmoticonController extends CController
* 自定义上传表情包
* @RequestMapping(path="upload-emoticon", methods="post")
*
* @param UploadService $uploadService
* @param Filesystem $filesystem
* @return ResponseInterface
*/
public function uploadEmoticon(UploadService $uploadService)
public function uploadEmoticon(Filesystem $filesystem)
{
$file = $this->request->file('emoticon');
if (!$file->isValid()) {
@ -164,20 +164,16 @@ class EmoticonController extends CController
);
}
// 读取图片信息
$imgInfo = @getimagesize($file->getRealPath());
if (!$imgInfo) {
return $this->response->fail('表情包上传失败!');
}
$save_path = $uploadService->media($file, 'media/images/emoticon', create_image_name($ext, $imgInfo[0], $imgInfo[1]));
if (!$save_path) {
try {
$path = 'media/images/emoticon/' . date('Ymd') . '/' . create_image_name($ext, getimagesize($file->getRealPath()));
$filesystem->write($path, file_get_contents($file->getRealPath()));
} catch (\Exception $e) {
return $this->response->fail('图片上传失败!');
}
$result = EmoticonDetail::create([
'user_id' => $this->uid(),
'url' => $save_path,
'url' => $path,
'file_suffix' => $ext,
'file_size' => $file->getSize(),
'created_at' => time()

View File

@ -17,7 +17,6 @@ use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\RequestMapping;
use Hyperf\HttpServer\Annotation\Middleware;
use App\Middleware\JWTAuthMiddleware;
use Hyperf\Utils\Str;
use Psr\Http\Message\ResponseInterface;
use App\Model\EmoticonDetail;
use App\Model\FileSplitUpload;
@ -26,9 +25,9 @@ use App\Model\UsersChatList;
use App\Model\UsersFriend;
use App\Model\Group\Group;
use App\Service\TalkService;
use App\Service\UploadService;
use App\Amqp\Producer\ChatMessageProducer;
use App\Constants\SocketConstants;
use League\Flysystem\Filesystem;
/**
* Class TalkController
@ -475,10 +474,10 @@ class TalkController extends CController
* 上传聊天对话图片(待优化)
* @RequestMapping(path="send-image", methods="post")
*
* @param UploadService $uploadService
* @param Filesystem $filesystem
* @return ResponseInterface
*/
public function sendImage(UploadService $uploadService)
public function sendImage(Filesystem $filesystem)
{
$params = $this->request->inputs(['source', 'receive_id']);
$this->validate($params, [
@ -496,11 +495,10 @@ class TalkController extends CController
return $this->response->fail('图片格式错误目前仅支持jpg、png、jpeg、gif和webp');
}
// 获取图片信息
$imgInfo = getimagesize($file->getRealPath());
$path = $uploadService->media($file, 'media/images/talks', create_image_name($ext, $imgInfo[0], $imgInfo[1]));
if (!$path) {
try {
$path = 'media/images/talks/' . date('Ymd') . '/' . create_image_name($ext, getimagesize($file->getRealPath()));
$filesystem->write($path, file_get_contents($file->getRealPath()));
} catch (\Exception $e) {
return $this->response->fail();
}
@ -593,10 +591,10 @@ class TalkController extends CController
* 发送文件消息
* @RequestMapping(path="send-file", methods="post")
*
* @param UploadService $uploadService
* @param Filesystem $filesystem
* @return ResponseInterface
*/
public function sendFile(UploadService $uploadService)
public function sendFile(Filesystem $filesystem)
{
$params = $this->request->inputs(['hash_name', 'receive_id', 'source']);
$this->validate($params, [
@ -612,12 +610,13 @@ class TalkController extends CController
return $this->response->fail('文件不存在...');
}
$file_hash_name = uniqid() . Str::random(10) . '.' . $file->file_ext;
$save_dir = "files/talks/" . date('Ymd') . '/' . $file_hash_name;
$save_dir = "files/talks/" . date('Ymd') . '/' . create_random_filename($file->file_ext);
$uploadService->makeDirectory($uploadService->driver("files/talks/" . date('Ymd')));
@copy($uploadService->driver($file->save_dir), $uploadService->driver($save_dir));
try {
$filesystem->copy($file->save_dir, $save_dir);
} catch (\Exception $e) {
return $this->response->fail('文件不存在...');
}
$record_id = $this->talkService->createFileMessage([
'source' => $params['source'],

View File

@ -17,12 +17,11 @@ use Hyperf\HttpServer\Annotation\RequestMapping;
use Hyperf\HttpServer\Annotation\Middleware;
use App\Middleware\JWTAuthMiddleware;
use App\Service\SplitUploadService;
use App\Service\UploadService;
use League\Flysystem\Filesystem;
use Psr\Http\Message\ResponseInterface;
/**
* 上传控制器
* Class UploadController
* 上传文件控制器
* @Controller(path="/api/v1/upload")
* @Middleware(JWTAuthMiddleware::class)
*
@ -30,12 +29,6 @@ use Psr\Http\Message\ResponseInterface;
*/
class UploadController extends CController
{
/**
* @inject
* @var UploadService
*/
private $uploadService;
/**
* @inject
* @var SplitUploadService
@ -48,14 +41,19 @@ class UploadController extends CController
*
* @return ResponseInterface
*/
public function fileStream()
public function fileStream(Filesystem $filesystem)
{
$fileStream = $this->request->post('fileStream', '');
$data = base64_decode(str_replace(['data:image/png;base64,', ' '], ['', '+'], $fileStream));
if (empty($fileStream)) {
return $this->response->fail();
}
$path = '/media/images/avatar/' . date('Ymd') . '/' . uniqid() . date('His') . '.png';
$this->uploadService->makeDirectory($this->uploadService->driver('/media/images/avatar/' . date('Ymd') . '/'));
@file_put_contents($this->uploadService->driver($path), $data);
$path = 'media/images/avatar/' . date('Ymd') . '/' . create_random_filename('png');
try {
$filesystem->write($path, base64_decode(str_replace(['data:image/png;base64,', ' '], ['', '+'], $fileStream)));
} catch (\Exception $e) {
return $this->response->fail();
}
return $this->response->success(['avatar' => get_media_url($path)]);
}
@ -105,7 +103,7 @@ class UploadController extends CController
$user_id = $this->uid();
$uploadRes = $this->splitUploadService->upload($user_id, $file, $params['hash'], intval($params['split_index']), intval($params['size']));
if (!$uploadRes) {
return $this->response->fail('上传文件失败');
return $this->response->fail('上传文件失败111');
}
if (($params['split_index'] + 1) == $params['split_num']) {

View File

@ -5,6 +5,7 @@ namespace App\Service;
use App\Model\FileSplitUpload;
use Hyperf\Utils\Str;
use Hyperf\HttpMessage\Upload\UploadedFile;
use League\Flysystem\Filesystem;
/**
* 文件拆分上传服务
@ -63,18 +64,12 @@ class SplitUploadService
->where([['user_id', '=', $user_id], ['hash_name', '=', $hashName], ['file_type', '=', 1]])
->first();
if (!$fileInfo) {
return false;
}
if (!$fileInfo) return false;
// 保存文件名及保存文件相对目录
$fileName = "{$hashName}_{$split_index}_{$fileInfo->file_ext}.tmp";
$uploadService = make(UploadService::class);
$uploadService->makeDirectory($uploadService->driver("tmp/{$hashName}"));
$file->moveTo(sprintf('%s/%s', $uploadService->driver("tmp/{$hashName}"), $fileName));
if (!$file->isMoved()) {
$save_path = "tmp/{$hashName}/" . "{$hashName}_{$split_index}_{$fileInfo->file_ext}.tmp";
try {
container()->get(Filesystem::class)->write($save_path, file_get_contents($file->getRealPath()));
} catch (\Exception $e) {
return false;
}
@ -87,7 +82,7 @@ class SplitUploadService
'original_name' => $fileInfo->original_name,
'split_index' => $split_index,
'split_num' => $fileInfo->split_num,
'save_dir' => sprintf('%s/%s', "tmp/{$hashName}", $fileName),
'save_dir' => $save_path,
'file_ext' => $fileInfo->file_ext,
'file_size' => $fileSize,
'upload_at' => time(),
@ -112,9 +107,7 @@ class SplitUploadService
->where('file_type', 1)
->first();
if (!$fileInfo) {
return false;
}
if (!$fileInfo) return false;
$files = FileSplitUpload::where('user_id', $user_id)
->where('hash_name', $hash_name)
@ -122,30 +115,27 @@ class SplitUploadService
->orderBy('split_index', 'asc')
->get(['split_index', 'save_dir'])->toArray();
if (!$files) {
return false;
}
if (!$files || count($files) != $fileInfo->split_num) return false;
if (count($files) != $fileInfo->split_num) {
return false;
}
$file_merge = "tmp/{$hash_name}/{$fileInfo->original_name}.tmp";
$fileMerge = "tmp/{$hash_name}/{$fileInfo->original_name}.tmp";
$uploadService = make(UploadService::class);
// 文件合并
$merge_save_path = $uploadService->driver($fileMerge);
$filesystem = container()->get(Filesystem::class);
$root_path = $filesystem->getConfig()->get('root');
foreach ($files as $file) {
file_put_contents($merge_save_path, file_get_contents($uploadService->driver($file['save_dir'])), FILE_APPEND);
file_put_contents(
"{$root_path}/{$file_merge}",
$filesystem->read($file['save_dir']),
FILE_APPEND
);
}
FileSplitUpload::select(['id', 'original_name', 'split_num', 'file_ext', 'file_size'])
->where('user_id', $user_id)->where('hash_name', $hash_name)
->where('file_type', 1)
->update(['save_dir' => $fileMerge]);
->update(['save_dir' => $file_merge]);
return [
'path' => $fileMerge,
'path' => $file_merge,
'tmp_file_name' => "{$fileInfo->original_name}.tmp",
'original_name' => $fileInfo->original_name,
'file_size' => $fileInfo->file_size

View File

@ -1,51 +0,0 @@
<?php
namespace App\Service;
use Hyperf\HttpMessage\Upload\UploadedFile;
/**
* 文件上传服务
*
* @package App\Service
*/
class UploadService extends BaseService
{
public function driver($dir)
{
return sprintf('%s/%s', rtrim(config('upload_dir'), '/'), trim($dir, '/'));
}
/**
* 创建文件夹
*
* @param string $dir 文件夹路径
*/
public function makeDirectory(string $dir)
{
if (!file_exists($dir)) @mkdir($dir, 0777, true);
}
/**
* 上传媒体图片
*
* @param UploadedFile $file
* @param string $dir 文件夹路径
* @param string $filename 文件名称
* @return bool|string
*/
public function media(UploadedFile $file, string $dir, string $filename)
{
$save_dir = $this->driver($dir);
$this->makeDirectory($save_dir);
$file->moveTo(sprintf('%s/%s', $save_dir, $filename));
if ($file->isMoved()) {
@chmod(sprintf('%s/%s', $save_dir, $filename), 0644);
}
return $file->isMoved() ? sprintf('%s/%s', trim($dir, '/'), $filename) : false;
}
}

View File

@ -49,7 +49,8 @@ class MailerTemplate
public function errorNotice(Throwable $throwable)
{
return $this->view(config('view.engine'), 'emails.error-notice', [
'throwable' => $throwable->getTraceAsString()
'throwable' => $throwable->getTraceAsString(),
'message' => $throwable->getMessage()
]);
}
}

View File

@ -180,14 +180,13 @@ function get_media_url(string $path)
/**
* 随机生成图片名
*
* @param string $ext 图片后缀名
* @param int $width 图片宽度
* @param int $height 图片高度
* @param string $ext 图片后缀名
* @param array $filesize 图片文件大小信息
* @return string
*/
function create_image_name(string $ext, int $width, int $height)
function create_image_name(string $ext, array $filesize)
{
return uniqid() . Str::random() . '_' . $width . 'x' . $height . '.' . $ext;
return uniqid() . Str::random() . '_' . $filesize[0] . 'x' . $filesize[1] . '.' . $ext;
}
/**
@ -255,4 +254,14 @@ function push_amqp(ProducerMessage $message, bool $confirm = false, int $timeout
return container()->get(Producer::class)->produce($message, $confirm, $timeout);
}
/**
* 生成随机文件名
*
* @param string $ext 文件后缀名
* @return string
*/
function create_random_filename(string $ext)
{
$ext = $ext ? '.' . $ext : '';
return Str::random(10) . uniqid() . $ext;
}

View File

@ -12,13 +12,13 @@ declare(strict_types=1);
return [
'default' => 'local',
'storage' => [
'local' => [
'local' => [
'driver' => \Hyperf\Filesystem\Adapter\LocalAdapterFactory::class,
'root' => __DIR__ . '/../../runtime',
'root' => env('UPLOAD_PATH', __DIR__ . '/../../runtime'),
],
'ftp' => [
'driver' => \Hyperf\Filesystem\Adapter\FtpAdapterFactory::class,
'host' => 'ftp.example.com',
'ftp' => [
'driver' => \Hyperf\Filesystem\Adapter\FtpAdapterFactory::class,
'host' => 'ftp.example.com',
'username' => 'username',
'password' => 'password',
// 'port' => 21,
@ -31,59 +31,59 @@ return [
'memory' => [
'driver' => \Hyperf\Filesystem\Adapter\MemoryAdapterFactory::class,
],
's3' => [
'driver' => \Hyperf\Filesystem\Adapter\S3AdapterFactory::class,
'credentials' => [
'key' => env('S3_KEY'),
's3' => [
'driver' => \Hyperf\Filesystem\Adapter\S3AdapterFactory::class,
'credentials' => [
'key' => env('S3_KEY'),
'secret' => env('S3_SECRET'),
],
'region' => env('S3_REGION'),
'version' => 'latest',
'bucket_endpoint' => false,
'region' => env('S3_REGION'),
'version' => 'latest',
'bucket_endpoint' => false,
'use_path_style_endpoint' => false,
'endpoint' => env('S3_ENDPOINT'),
'bucket_name' => env('S3_BUCKET'),
'endpoint' => env('S3_ENDPOINT'),
'bucket_name' => env('S3_BUCKET'),
],
'minio' => [
'driver' => \Hyperf\Filesystem\Adapter\S3AdapterFactory::class,
'credentials' => [
'key' => env('S3_KEY'),
'minio' => [
'driver' => \Hyperf\Filesystem\Adapter\S3AdapterFactory::class,
'credentials' => [
'key' => env('S3_KEY'),
'secret' => env('S3_SECRET'),
],
'region' => env('S3_REGION'),
'version' => 'latest',
'bucket_endpoint' => false,
'region' => env('S3_REGION'),
'version' => 'latest',
'bucket_endpoint' => false,
'use_path_style_endpoint' => true,
'endpoint' => env('S3_ENDPOINT'),
'bucket_name' => env('S3_BUCKET'),
'endpoint' => env('S3_ENDPOINT'),
'bucket_name' => env('S3_BUCKET'),
],
'oss' => [
'driver' => \Hyperf\Filesystem\Adapter\AliyunOssAdapterFactory::class,
'accessId' => env('OSS_ACCESS_ID'),
'oss' => [
'driver' => \Hyperf\Filesystem\Adapter\AliyunOssAdapterFactory::class,
'accessId' => env('OSS_ACCESS_ID'),
'accessSecret' => env('OSS_ACCESS_SECRET'),
'bucket' => env('OSS_BUCKET'),
'endpoint' => env('OSS_ENDPOINT'),
'bucket' => env('OSS_BUCKET'),
'endpoint' => env('OSS_ENDPOINT'),
// 'timeout' => 3600,
// 'connectTimeout' => 10,
// 'isCName' => false,
// 'token' => '',
],
'qiniu' => [
'driver' => \Hyperf\Filesystem\Adapter\QiniuAdapterFactory::class,
'qiniu' => [
'driver' => \Hyperf\Filesystem\Adapter\QiniuAdapterFactory::class,
'accessKey' => env('QINIU_ACCESS_KEY'),
'secretKey' => env('QINIU_SECRET_KEY'),
'bucket' => env('QINIU_BUCKET'),
'domain' => env('QINBIU_DOMAIN'),
'bucket' => env('QINIU_BUCKET'),
'domain' => env('QINBIU_DOMAIN'),
],
'cos' => [
'driver' => \Hyperf\Filesystem\Adapter\CosAdapterFactory::class,
'region' => env('COS_REGION'),
'credentials' => [
'appId' => env('COS_APPID'),
'secretId' => env('COS_SECRET_ID'),
'cos' => [
'driver' => \Hyperf\Filesystem\Adapter\CosAdapterFactory::class,
'region' => env('COS_REGION'),
'credentials' => [
'appId' => env('COS_APPID'),
'secretId' => env('COS_SECRET_ID'),
'secretKey' => env('COS_SECRET_KEY'),
],
'bucket' => env('COS_BUCKET'),
'bucket' => env('COS_BUCKET'),
'read_from_cdn' => false,
// 'timeout' => 60,
// 'connect_timeout' => 60,

View File

@ -21,14 +21,12 @@ return [
// 域名相关配置
'domain' => [
'web_url' => env('WEB_URL', ''),//Web 端首页地址
'img_url' => env('IMG_URL', ''),//设置文件图片访问的域名
'web_url' => env('WEB_URL', ''),// Web 端首页地址
'img_url' => env('IMG_URL', ''),// 设置文件图片访问的域名
],
'upload_dir' => env('UPLOAD_PATH', ''),
// 管理员邮箱
'admin_email' => env('ADMIN_EMAIL', ''),
'admin_email' => env('ADMIN_EMAIL', ''),
StdoutLoggerInterface::class => [
'log_level' => [

View File

@ -70,6 +70,7 @@
</strong>
</div>
<div style="margin-bottom:30px;">
<p>{{$message}}</p>
<pre>{{$throwable}}</pre>
</div>
</div>