diff --git a/app/Http/Controllers/TopicsController.php b/app/Http/Controllers/TopicsController.php index e1f0714..5335236 100644 --- a/app/Http/Controllers/TopicsController.php +++ b/app/Http/Controllers/TopicsController.php @@ -28,8 +28,11 @@ class TopicsController extends Controller return view('topics.index', compact('topics')); } - public function show(Topic $topic) + public function show(Topic $topic, Request $request) { + if (!empty($topic->slug) && $topic->slug != $request->slug) { + return redirect($topic->link(), 301); + } return view('topics.show', compact('topic')); } @@ -38,7 +41,7 @@ class TopicsController extends Controller $topic->fill($request->all()); $topic->user_id = Auth::id(); $topic->save(); - return redirect()->route('topics.show', $topic->id)->with('success', '添加成功!.'); + return redirect()->to($topic->link())->with('success', '添加成功!.'); } public function edit(Topic $topic) @@ -75,7 +78,7 @@ class TopicsController extends Controller $this->authorize('update', $topic); $topic->update($request->all()); - return redirect()->route('topics.show', $topic->id)->with('success', '编辑成功!.'); + return redirect()->route('topics.show', [$topic->id, $topic->slug])->with('success', '编辑成功!'); } public function destroy(Topic $topic) @@ -83,6 +86,6 @@ class TopicsController extends Controller $this->authorize('destroy', $topic); $topic->delete(); - return redirect()->route('topics.index')->with('message', 'Deleted successfully.'); + return redirect()->route('topics.index')->with('message', '删除成功.'); } } \ No newline at end of file diff --git a/app/Models/Topic.php b/app/Models/Topic.php index a5b7a7f..3f080c4 100644 --- a/app/Models/Topic.php +++ b/app/Models/Topic.php @@ -7,6 +7,11 @@ class Topic extends Model protected $fillable = ['title', 'category_id', 'body', 'excerpt', 'slug']; + public function link($params = []) + { + return route('topics.show', array_merge([$this->id, $this->slug], $params)); + } + public function scopeWithOrder($query, $order) { // 不同的排序,使用不同的数据读取逻辑 diff --git a/app/Models/User.php b/app/Models/User.php index 31ba0e5..257bc49 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -32,6 +32,11 @@ class User extends Authenticatable return asset($this->avatar); } + public function isAuthorOf($model) + { + return $this->id == $model->user_id; + } + public function topics() { return $this->hasMany(Topic::class); diff --git a/app/Observers/TopicObserver.php b/app/Observers/TopicObserver.php index c1f1259..54b2860 100644 --- a/app/Observers/TopicObserver.php +++ b/app/Observers/TopicObserver.php @@ -3,6 +3,7 @@ namespace App\Observers; use App\Models\Topic; +use App\Tools\SlugTranslateHandler; // creating, created, updating, updated, saving, // saved, deleting, deleted, restoring, restored @@ -18,6 +19,10 @@ class TopicObserver { $topic->body = clean($topic->body, 'user_topic_body'); $topic->excerpt = make_excerpt($topic->body); + // 如 slug 字段无内容,即使用翻译器对 title 进行翻译 + if (!$topic->slug) { + $topic->slug = app(SlugTranslateHandler::class)->translate($topic->title); + } } public function updating(Topic $topic) diff --git a/app/Policies/TopicPolicy.php b/app/Policies/TopicPolicy.php index 803919a..a2ccc80 100644 --- a/app/Policies/TopicPolicy.php +++ b/app/Policies/TopicPolicy.php @@ -9,11 +9,11 @@ class TopicPolicy extends Policy { public function update(User $user, Topic $topic) { - return $topic->user_id == $user->id; + return $user->isAuthorOf($topic); } public function destroy(User $user, Topic $topic) { - return true; + return $user->isAuthorOf($topic); } } diff --git a/app/Tools/SlugTranslateHandler.php b/app/Tools/SlugTranslateHandler.php new file mode 100644 index 0000000..8a42e8e --- /dev/null +++ b/app/Tools/SlugTranslateHandler.php @@ -0,0 +1,81 @@ +pinyin($text); + } + + // 根据文档,生成 sign + // http://api.fanyi.baidu.com/api/trans/product/apidoc + // appid+q+salt+密钥 的MD5值 + $sign = md5($appid . $text . $salt . $key); + + // 构建请求参数 + $query = http_build_query([ + "q" => $text, + "from" => "zh", + "to" => "en", + "appid" => $appid, + "salt" => $salt, + "sign" => $sign, + ]); + + // 发送 HTTP Get 请求 + $response = $http->get($api . $query); + + $result = json_decode($response->getBody(), true); + + /** + * 获取结果,如果请求成功,dd($result) 结果如下: + * + * array:3 [▼ + * "from" => "zh" + * "to" => "en" + * "trans_result" => array:1 [▼ + * 0 => array:2 [▼ + * "src" => "XSS 安全漏洞" + * "dst" => "XSS security vulnerability" + * ] + * ] + * ] + **/ + + // 尝试获取获取翻译结果 + if (isset($result['trans_result'][0]['dst'])) { + return str_slug($result['trans_result'][0]['dst']); + } else { + // 如果百度翻译没有结果,使用拼音作为后备计划。 + return $this->pinyin($text); + } + } + + public function pinyin($text) + { + return str_slug(app(Pinyin::class)->permalink($text)); + } +} diff --git a/composer.json b/composer.json index 22bf8c1..079684b 100644 --- a/composer.json +++ b/composer.json @@ -11,13 +11,15 @@ "php": ">=7.0.0", "doctrine/dbal": "^2.6", "fideloper/proxy": "~3.3", + "guzzlehttp/guzzle": "~6.3", "hieu-le/active": "~3.5", "intervention/image": "^2.4", "laravel/framework": "5.5.*", "laravel/tinker": "~1.0", "mews/captcha": "~2.0", "mews/purifier": "~2.0", - "overtrue/laravel-lang": "^3.0" + "overtrue/laravel-lang": "^3.0", + "overtrue/pinyin": "~3.0" }, "require-dev": { "barryvdh/laravel-debugbar": "^3.1", diff --git a/composer.lock b/composer.lock index e8e3a06..8e6e22e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "0623f829dd1042d2c133664fd6525faa", + "content-hash": "8d5baf0bc06734b3359648bb624b4f3c", "packages": [ { "name": "caouecs/laravel-lang", @@ -763,6 +763,122 @@ ], "time": "2017-06-15T17:19:42+00:00" }, + { + "name": "guzzlehttp/guzzle", + "version": "6.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699", + "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.0 || ^5.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.2-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2017-06-22T18:50:49+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-12-20T10:07:11+00:00" + }, { "name": "guzzlehttp/psr7", "version": "1.4.2", @@ -1747,6 +1863,51 @@ ], "time": "2017-10-28T12:10:43+00:00" }, + { + "name": "overtrue/pinyin", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/overtrue/pinyin.git", + "reference": "3b781d267197b74752daa32814d3a2cf5d140779" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/overtrue/pinyin/zipball/3b781d267197b74752daa32814d3a2cf5d140779", + "reference": "3b781d267197b74752daa32814d3a2cf5d140779", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Overtrue\\Pinyin\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Carlos", + "homepage": "http://github.com/overtrue" + } + ], + "description": "Chinese to pinyin translator.", + "homepage": "https://github.com/overtrue/pinyin", + "keywords": [ + "Chinese", + "Pinyin", + "cn2pinyin" + ], + "time": "2017-07-10T07:20:01+00:00" + }, { "name": "paragonie/random_compat", "version": "v2.0.11", diff --git a/config/services.php b/config/services.php index 4b5f049..aa4b0f8 100644 --- a/config/services.php +++ b/config/services.php @@ -14,6 +14,11 @@ return [ | */ + 'baidu_translate' => [ + 'appid' => env('BAIDU_TRANSLATE_APPID'), + 'key' => env('BAIDU_TRANSLATE_KEY'), + ], + 'mailgun' => [ 'domain' => env('MAILGUN_DOMAIN'), 'secret' => env('MAILGUN_SECRET'), diff --git a/resources/views/topics/create_and_edit.blade.php b/resources/views/topics/create_and_edit.blade.php index 40742d2..2a71eb8 100644 --- a/resources/views/topics/create_and_edit.blade.php +++ b/resources/views/topics/create_and_edit.blade.php @@ -62,7 +62,7 @@ diff --git a/resources/views/topics/show.blade.php b/resources/views/topics/show.blade.php index 1250e68..a5c7b61 100644 --- a/resources/views/topics/show.blade.php +++ b/resources/views/topics/show.blade.php @@ -42,15 +42,24 @@ {!! $topic->body !!} -
+ @can('update', $topic) +