diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 76aceb5..c20ce74 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; -use App\User; +use App\Models\User; use Illuminate\Foundation\Auth\RegistersUsers; use Illuminate\Support\Facades\Validator; @@ -48,9 +48,13 @@ class RegisterController extends Controller protected function validator(array $data) { return Validator::make($data, [ - 'name' => 'required|string|max:255', + 'name' => 'required|unique:users|string|max:255', 'email' => 'required|string|email|max:255|unique:users', 'password' => 'required|string|min:6|confirmed', + 'captcha' => 'required|captcha' + ], [ + 'captcha.required' => '验证码不能为空', + 'captcha.captcha' => '请输入正确的验证码', ]); } @@ -58,7 +62,7 @@ class RegisterController extends Controller * Create a new user instance after a valid registration. * * @param array $data - * @return \App\User + * @return \App\Models\User */ protected function create(array $data) { diff --git a/app/Http/Controllers/UsersController.php b/app/Http/Controllers/UsersController.php new file mode 100644 index 0000000..a8b0cd0 --- /dev/null +++ b/app/Http/Controllers/UsersController.php @@ -0,0 +1,30 @@ +only(['name', 'email', 'introduction']); + if ($request->file('avatar')) { + $user->avatar = $request->file('avatar')->store('public/avatar'); + } + $user->update($attribute); + return redirect()->route('users.show', [$user])->with('success', '更新成功!'); + + } +} diff --git a/app/Http/Requests/UserUpdate.php b/app/Http/Requests/UserUpdate.php new file mode 100644 index 0000000..3569ebf --- /dev/null +++ b/app/Http/Requests/UserUpdate.php @@ -0,0 +1,45 @@ + ['required', 'min:3', 'max:20', + 'regex:/^[0-9A-Za-z\-\_]+$/', + 'unique:users,name,' . Auth::id() + ], + 'email' => ['required', 'unique:users,email,' . Auth::id()], + 'introduction' => 'nullable|max:255', + 'avatar' => 'image|nullable', + ]; + } + + + public function attributes() + { + return [ + 'introduction' => '简介', + ]; + } +} diff --git a/app/User.php b/app/Models/User.php similarity index 72% rename from app/User.php rename to app/Models/User.php index abafe7c..e35be7f 100644 --- a/app/User.php +++ b/app/Models/User.php @@ -1,6 +1,6 @@ avatar); + } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 35471f6..3cdecc2 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,6 +2,7 @@ namespace App\Providers; +use Carbon\Carbon; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider @@ -13,7 +14,7 @@ class AppServiceProvider extends ServiceProvider */ public function boot() { - // + Carbon::setLocale('zh'); } /** diff --git a/app/Tools/ImageUploadTool.php b/app/Tools/ImageUploadTool.php new file mode 100644 index 0000000..a7c6d1b --- /dev/null +++ b/app/Tools/ImageUploadTool.php @@ -0,0 +1,55 @@ +getClientOriginalExtension()) ?: 'png'; + + // 拼接文件名,加前缀是为了增加辨析度,前缀可以是相关数据模型的 ID + // 值如:1_1493521050_7BVc9v9ujP.png + $filename = $file_prefix . '_' . time() . '_' . str_random(10) . '.' . $extension; + + // 如果上传的不是图片将终止操作 + if (!in_array($extension, $this->allowed_ext)) { + return false; + } + + // 将图片移动到我们的目标存储路径中 + $file->move($upload_path, $filename); + + return [ + 'path' => config('app.url') . "/$folder_name/$filename" + ]; + } +} \ No newline at end of file diff --git a/composer.json b/composer.json index 41201a1..8391dc4 100644 --- a/composer.json +++ b/composer.json @@ -10,8 +10,10 @@ "require": { "php": ">=7.0.0", "fideloper/proxy": "~3.3", + "intervention/image": "^2.4", "laravel/framework": "5.5.*", "laravel/tinker": "~1.0", + "mews/captcha": "~2.0", "overtrue/laravel-lang": "^3.0" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 06032d6..5bc1f4b 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": "248c18e4b26c8ecaedb1b6564a2ae6ac", + "content-hash": "30c482e9d01b8a7536eab6f658b9ce1c", "packages": [ { "name": "caouecs/laravel-lang", @@ -361,6 +361,141 @@ ], "time": "2017-06-15T17:19:42+00:00" }, + { + "name": "guzzlehttp/psr7", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "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" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2017-03-20T17:10:46+00:00" + }, + { + "name": "intervention/image", + "version": "2.4.1", + "source": { + "type": "git", + "url": "https://github.com/Intervention/image.git", + "reference": "3603dbcc9a17d307533473246a6c58c31cf17919" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Intervention/image/zipball/3603dbcc9a17d307533473246a6c58c31cf17919", + "reference": "3603dbcc9a17d307533473246a6c58c31cf17919", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "guzzlehttp/psr7": "~1.1", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "~0.9.2", + "phpunit/phpunit": "^4.8 || ^5.7" + }, + "suggest": { + "ext-gd": "to use GD library based image processing.", + "ext-imagick": "to use Imagick based image processing.", + "intervention/imagecache": "Caching extension for the Intervention Image library" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + }, + "laravel": { + "providers": [ + "Intervention\\Image\\ImageServiceProvider" + ], + "aliases": { + "Image": "Intervention\\Image\\Facades\\Image" + } + } + }, + "autoload": { + "psr-4": { + "Intervention\\Image\\": "src/Intervention/Image" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oliver Vogel", + "email": "oliver@olivervogel.com", + "homepage": "http://olivervogel.com/" + } + ], + "description": "Image handling and manipulation library with support for Laravel integration", + "homepage": "http://image.intervention.io/", + "keywords": [ + "gd", + "image", + "imagick", + "laravel", + "thumbnail", + "watermark" + ], + "time": "2017-09-21T16:29:17+00:00" + }, { "name": "jakub-onderka/php-console-color", "version": "0.1", @@ -728,6 +863,73 @@ ], "time": "2017-08-06T17:41:04+00:00" }, + { + "name": "mews/captcha", + "version": "2.1.7", + "source": { + "type": "git", + "url": "https://github.com/mewebstudio/captcha.git", + "reference": "7d48d7dc5df0fb2225b086ba85cb3fef9832b235" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mewebstudio/captcha/zipball/7d48d7dc5df0fb2225b086ba85cb3fef9832b235", + "reference": "7d48d7dc5df0fb2225b086ba85cb3fef9832b235", + "shasum": "" + }, + "require": { + "ext-gd": "*", + "illuminate/config": "~5.0", + "illuminate/filesystem": "~5.0", + "illuminate/hashing": "~5.0", + "illuminate/support": "~5.0", + "intervention/image": "~2.2", + "php": ">=5.4" + }, + "require-dev": { + "mockery/mockery": "0.9.*", + "phpunit/phpunit": "~4.1" + }, + "type": "package", + "extra": { + "laravel": { + "providers": [ + "Mews\\Captcha\\CaptchaServiceProvider" + ], + "aliases": { + "Captcha": "Mews\\Captcha\\Facades\\Captcha" + } + } + }, + "autoload": { + "psr-4": { + "Mews\\Captcha\\": "src/" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Muharrem ERİN", + "email": "me@mewebstudio.com", + "homepage": "https://github.com/mewebstudio", + "role": "Developer" + } + ], + "description": "Laravel 5 Captcha Package", + "homepage": "https://github.com/mewebstudio/captcha", + "keywords": [ + "captcha", + "laravel5 Captcha", + "laravel5 Security" + ], + "time": "2017-09-11T14:59:20+00:00" + }, { "name": "monolog/monolog", "version": "1.23.0", @@ -1102,6 +1304,56 @@ ], "time": "2017-02-14T16:28:37+00:00" }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, { "name": "psr/log", "version": "1.0.2", diff --git a/config/auth.php b/config/auth.php index 7817501..087bbb3 100644 --- a/config/auth.php +++ b/config/auth.php @@ -67,7 +67,7 @@ return [ 'providers' => [ 'users' => [ 'driver' => 'eloquent', - 'model' => App\User::class, + 'model' => App\Models\User::class, ], // 'users' => [ diff --git a/config/captcha.php b/config/captcha.php new file mode 100644 index 0000000..2d0ec0c --- /dev/null +++ b/config/captcha.php @@ -0,0 +1,45 @@ + '2346789abcdefghjmnpqrtuxyzABCDEFGHJMNPQRTUXYZ', + + 'default' => [ + 'length' => 4, + 'width' => 120, + 'height' => 36, + 'quality' => 90, + ], + + 'flat' => [ + 'length' => 6, + 'width' => 160, + 'height' => 46, + 'quality' => 90, + 'lines' => 6, + 'bgImage' => false, + 'bgColor' => '#ecf2f4', + 'fontColors' => ['#2c3e50', '#c0392b', '#16a085', '#c0392b', '#8e44ad', '#303f9f', '#f57c00', '#795548'], + 'contrast' => -5, + ], + + 'mini' => [ + 'length' => 3, + 'width' => 60, + 'height' => 32, + ], + + 'inverse' => [ + 'length' => 5, + 'width' => 120, + 'height' => 36, + 'quality' => 90, + 'sensitive' => true, + 'angle' => 12, + 'sharpen' => 10, + 'blur' => 2, + 'invert' => true, + 'contrast' => -5, + ] + +]; diff --git a/config/image.php b/config/image.php new file mode 100644 index 0000000..2b1d2c3 --- /dev/null +++ b/config/image.php @@ -0,0 +1,20 @@ + 'gd' + +]; diff --git a/config/services.php b/config/services.php index 4460f0e..4b5f049 100644 --- a/config/services.php +++ b/config/services.php @@ -30,7 +30,7 @@ return [ ], 'stripe' => [ - 'model' => App\User::class, + 'model' => App\Models\User::class, 'key' => env('STRIPE_KEY'), 'secret' => env('STRIPE_SECRET'), ], diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 061d75a..0a54d00 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -13,7 +13,7 @@ use Faker\Generator as Faker; | */ -$factory->define(App\User::class, function (Faker $faker) { +$factory->define(App\Models\User::class, function (Faker $faker) { static $password; return [ diff --git a/database/migrations/2017_12_31_002134_add_avatar_and_introduction_to_users_table.php b/database/migrations/2017_12_31_002134_add_avatar_and_introduction_to_users_table.php new file mode 100644 index 0000000..5fce7e0 --- /dev/null +++ b/database/migrations/2017_12_31_002134_add_avatar_and_introduction_to_users_table.php @@ -0,0 +1,34 @@ +string('avatar')->nullable(); + $table->string('introduction')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('avatar'); + $table->dropColumn('introduction'); + }); + } +} diff --git a/public/css/app.css b/public/css/app.css index eba4235..d24ece9 100644 --- a/public/css/app.css +++ b/public/css/app.css @@ -8405,3 +8405,17 @@ body { margin-top: 0px; } +/* User register page */ + +.register-page img.captcha { + margin-bottom: 0px; + margin-top: 10px; + cursor: pointer; +} + +/* User profile page */ + +.users-show-page .user-info .thumbnail { + margin-bottom: 0px; +} + diff --git a/public/js/app.js b/public/js/app.js index 3ff2c33..11ca34b 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -21554,6 +21554,7 @@ var rnothtmlwhite = (/[^\x20\t\r\n\f]+/g); + // Convert String-formatted options into Object-formatted ones function createOptions(options) { var object = {}; @@ -22185,6 +22186,8 @@ }; + + // The deferred used on DOM ready var readyList = jQuery.Deferred(); @@ -22262,6 +22265,8 @@ } + + // Multifunctional method to get and set values of a collection // The value/s can optionally be executed if it's a function var access = function (elems, fn, key, value, chainable, emptyGet, raw) { @@ -22489,6 +22494,7 @@ var dataUser = new Data(); + // Implementation Summary // // 1. Enforce API surface and semantic compatibility with 1.9.x branch @@ -23003,6 +23009,7 @@ var rscriptType = (/^$|\/(?:java|ecma)script/i); + // We have to close these tags to support XHTML (#13200) var wrapMap = { @@ -26400,6 +26407,8 @@ }); + + // Return jQuery for attributes-only inclusion @@ -26646,6 +26655,7 @@ var rquery = (/\?/); + // Cross-browser xml parsing jQuery.parseXML = function (data) { var xml; @@ -27875,6 +27885,8 @@ }); + + // Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) jQuery.ajaxPrefilter(function (s) { if (s.crossDomain) { @@ -28037,6 +28049,8 @@ }); + + // Support: Safari 8 only // In Safari 8 documents created via document.implementation.createHTMLDocument // collapse sibling forms: the second one becomes a child of the first one. @@ -28164,6 +28178,8 @@ }; + + // Attach a bunch of functions for handling common AJAX events jQuery.each([ "ajaxStart", @@ -28475,6 +28491,8 @@ jQuery.nodeName = nodeName; + + // Register as a named AMD module, since jQuery can be concatenated with other // files that may use define, but not via a proper concatenation script that // understands anonymous AMD modules. A named AMD is safest and most robust @@ -35918,6 +35936,8 @@ /* */ + + // Register the component hook to weex native render engine. // The hook will be triggered by native, not javascript. diff --git a/resources/assets/sass/app.scss b/resources/assets/sass/app.scss index 59dc445..cc37b2d 100644 --- a/resources/assets/sass/app.scss +++ b/resources/assets/sass/app.scss @@ -54,4 +54,22 @@ body { border-top: 4px solid #00b5ad; margin-bottom: 40px; margin-top: 0px; +} + +/* User register page */ +.register-page { + img.captcha { + margin-bottom: 0px; + margin-top: 10px; + cursor: pointer; + } +} + +/* User profile page */ +.users-show-page { + .user-info { + .thumbnail { + margin-bottom: 0px; + } + } } \ No newline at end of file diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php index e617f82..ae8454b 100644 --- a/resources/views/auth/register.blade.php +++ b/resources/views/auth/register.blade.php @@ -5,14 +5,14 @@