Showing
16 changed files
with
219 additions
and
57 deletions
| ... | @@ -33,6 +33,9 @@ GOOGLE_APP_SECRET=false | ... | @@ -33,6 +33,9 @@ GOOGLE_APP_SECRET=false |
| 33 | # URL used for social login redirects, NO TRAILING SLASH | 33 | # URL used for social login redirects, NO TRAILING SLASH |
| 34 | APP_URL=http://bookstack.dev | 34 | APP_URL=http://bookstack.dev |
| 35 | 35 | ||
| 36 | +# External services | ||
| 37 | +USE_GRAVATAR=true | ||
| 38 | + | ||
| 36 | # Mail settings | 39 | # Mail settings |
| 37 | MAIL_DRIVER=smtp | 40 | MAIL_DRIVER=smtp |
| 38 | MAIL_HOST=localhost | 41 | MAIL_HOST=localhost | ... | ... |
| ... | @@ -33,7 +33,7 @@ class ImageController extends Controller | ... | @@ -33,7 +33,7 @@ class ImageController extends Controller |
| 33 | 33 | ||
| 34 | 34 | ||
| 35 | /** | 35 | /** |
| 36 | - * Get all gallery images, Paginated | 36 | + * Get all images for a specific type, Paginated |
| 37 | * @param int $page | 37 | * @param int $page |
| 38 | * @return \Illuminate\Http\JsonResponse | 38 | * @return \Illuminate\Http\JsonResponse |
| 39 | */ | 39 | */ |
| ... | @@ -43,6 +43,17 @@ class ImageController extends Controller | ... | @@ -43,6 +43,17 @@ class ImageController extends Controller |
| 43 | return response()->json($imgData); | 43 | return response()->json($imgData); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | + /** | ||
| 47 | + * Get all images for a user. | ||
| 48 | + * @param int $page | ||
| 49 | + * @return \Illuminate\Http\JsonResponse | ||
| 50 | + */ | ||
| 51 | + public function getAllForUserType($page = 0) | ||
| 52 | + { | ||
| 53 | + $imgData = $this->imageRepo->getPaginatedByType('user', $page, 24, $this->currentUser->id); | ||
| 54 | + return response()->json($imgData); | ||
| 55 | + } | ||
| 56 | + | ||
| 46 | 57 | ||
| 47 | /** | 58 | /** |
| 48 | * Handles image uploads for use on pages. | 59 | * Handles image uploads for use on pages. | ... | ... |
| ... | @@ -62,7 +62,7 @@ class UserController extends Controller | ... | @@ -62,7 +62,7 @@ class UserController extends Controller |
| 62 | $this->checkPermission('user-create'); | 62 | $this->checkPermission('user-create'); |
| 63 | $this->validate($request, [ | 63 | $this->validate($request, [ |
| 64 | 'name' => 'required', | 64 | 'name' => 'required', |
| 65 | - 'email' => 'required|email', | 65 | + 'email' => 'required|email|unique:users,email', |
| 66 | 'password' => 'required|min:5', | 66 | 'password' => 'required|min:5', |
| 67 | 'password-confirm' => 'required|same:password', | 67 | 'password-confirm' => 'required|same:password', |
| 68 | 'role' => 'required|exists:roles,id' | 68 | 'role' => 'required|exists:roles,id' | ... | ... |
| ... | @@ -57,6 +57,9 @@ Route::group(['middleware' => 'auth'], function () { | ... | @@ -57,6 +57,9 @@ Route::group(['middleware' => 'auth'], function () { |
| 57 | 57 | ||
| 58 | // Image routes | 58 | // Image routes |
| 59 | Route::group(['prefix' => 'images'], function() { | 59 | Route::group(['prefix' => 'images'], function() { |
| 60 | + // Get for user images | ||
| 61 | + Route::get('/user/all', 'ImageController@getAllForUserType'); | ||
| 62 | + Route::get('/user/all/{page}', 'ImageController@getAllForUserType'); | ||
| 60 | // Standard get, update and deletion for all types | 63 | // Standard get, update and deletion for all types |
| 61 | Route::get('/thumb/{id}/{width}/{height}/{crop}', 'ImageController@getThumbnail'); | 64 | Route::get('/thumb/{id}/{width}/{height}/{crop}', 'ImageController@getThumbnail'); |
| 62 | Route::put('/update/{imageId}', 'ImageController@update'); | 65 | Route::put('/update/{imageId}', 'ImageController@update'); | ... | ... |
| ... | @@ -3,9 +3,10 @@ | ... | @@ -3,9 +3,10 @@ |
| 3 | namespace BookStack; | 3 | namespace BookStack; |
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | +use Illuminate\Database\Eloquent\Model; | ||
| 6 | use Images; | 7 | use Images; |
| 7 | 8 | ||
| 8 | -class Image | 9 | +class Image extends Model |
| 9 | { | 10 | { |
| 10 | use Ownable; | 11 | use Ownable; |
| 11 | 12 | ||
| ... | @@ -16,9 +17,10 @@ class Image | ... | @@ -16,9 +17,10 @@ class Image |
| 16 | * @param int $width | 17 | * @param int $width |
| 17 | * @param int $height | 18 | * @param int $height |
| 18 | * @param bool|false $hardCrop | 19 | * @param bool|false $hardCrop |
| 20 | + * @return string | ||
| 19 | */ | 21 | */ |
| 20 | public function getThumb($width, $height, $hardCrop = false) | 22 | public function getThumb($width, $height, $hardCrop = false) |
| 21 | { | 23 | { |
| 22 | - Images::getThumbnail($this, $width, $height, $hardCrop); | 24 | + return Images::getThumbnail($this, $width, $height, $hardCrop); |
| 23 | } | 25 | } |
| 24 | } | 26 | } | ... | ... |
| ... | @@ -17,7 +17,7 @@ class ImageRepo | ... | @@ -17,7 +17,7 @@ class ImageRepo |
| 17 | * @param Image $image | 17 | * @param Image $image |
| 18 | * @param ImageService $imageService | 18 | * @param ImageService $imageService |
| 19 | */ | 19 | */ |
| 20 | - public function __construct(Image $image,ImageService $imageService) | 20 | + public function __construct(Image $image, ImageService $imageService) |
| 21 | { | 21 | { |
| 22 | $this->image = $image; | 22 | $this->image = $image; |
| 23 | $this->imageService = $imageService; | 23 | $this->imageService = $imageService; |
| ... | @@ -40,12 +40,18 @@ class ImageRepo | ... | @@ -40,12 +40,18 @@ class ImageRepo |
| 40 | * @param string $type | 40 | * @param string $type |
| 41 | * @param int $page | 41 | * @param int $page |
| 42 | * @param int $pageSize | 42 | * @param int $pageSize |
| 43 | + * @param bool|int $userFilter | ||
| 43 | * @return array | 44 | * @return array |
| 44 | */ | 45 | */ |
| 45 | - public function getPaginatedByType($type, $page = 0, $pageSize = 24) | 46 | + public function getPaginatedByType($type, $page = 0, $pageSize = 24, $userFilter = false) |
| 46 | { | 47 | { |
| 47 | - $images = $this->image->where('type', '=', strtolower($type)) | 48 | + $images = $this->image->where('type', '=', strtolower($type)); |
| 48 | - ->orderBy('created_at', 'desc')->skip($pageSize * $page)->take($pageSize + 1)->get(); | 49 | + |
| 50 | + if ($userFilter !== false) { | ||
| 51 | + $images = $images->where('created_by', '=', $userFilter); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + $images = $images->orderBy('created_at', 'desc')->skip($pageSize * $page)->take($pageSize + 1)->get(); | ||
| 49 | $hasMore = count($images) > $pageSize; | 55 | $hasMore = count($images) > $pageSize; |
| 50 | 56 | ||
| 51 | $returnImages = $images->take(24); | 57 | $returnImages = $images->take(24); |
| ... | @@ -67,7 +73,7 @@ class ImageRepo | ... | @@ -67,7 +73,7 @@ class ImageRepo |
| 67 | */ | 73 | */ |
| 68 | public function saveNew(UploadedFile $uploadFile, $type) | 74 | public function saveNew(UploadedFile $uploadFile, $type) |
| 69 | { | 75 | { |
| 70 | - $image = $this->imageService->saveNew($this->image, $uploadFile, $type); | 76 | + $image = $this->imageService->saveNewFromUpload($uploadFile, $type); |
| 71 | $this->loadThumbs($image); | 77 | $this->loadThumbs($image); |
| 72 | return $image; | 78 | return $image; |
| 73 | } | 79 | } | ... | ... |
| 1 | <?php namespace BookStack\Services; | 1 | <?php namespace BookStack\Services; |
| 2 | 2 | ||
| 3 | use BookStack\Image; | 3 | use BookStack\Image; |
| 4 | +use BookStack\User; | ||
| 4 | use Intervention\Image\ImageManager; | 5 | use Intervention\Image\ImageManager; |
| 5 | use Illuminate\Contracts\Filesystem\Factory as FileSystem; | 6 | use Illuminate\Contracts\Filesystem\Factory as FileSystem; |
| 6 | use Illuminate\Contracts\Filesystem\Filesystem as FileSystemInstance; | 7 | use Illuminate\Contracts\Filesystem\Filesystem as FileSystemInstance; |
| ... | @@ -34,11 +35,48 @@ class ImageService | ... | @@ -34,11 +35,48 @@ class ImageService |
| 34 | $this->cache = $cache; | 35 | $this->cache = $cache; |
| 35 | } | 36 | } |
| 36 | 37 | ||
| 37 | - public function saveNew(Image $image, UploadedFile $uploadedFile, $type) | 38 | + /** |
| 39 | + * Saves a new image from an upload. | ||
| 40 | + * @param UploadedFile $uploadedFile | ||
| 41 | + * @param string $type | ||
| 42 | + * @return mixed | ||
| 43 | + */ | ||
| 44 | + public function saveNewFromUpload(UploadedFile $uploadedFile, $type) | ||
| 45 | + { | ||
| 46 | + $imageName = $uploadedFile->getClientOriginalName(); | ||
| 47 | + $imageData = file_get_contents($uploadedFile->getRealPath()); | ||
| 48 | + return $this->saveNew($imageName, $imageData, $type); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + | ||
| 52 | + /** | ||
| 53 | + * Gets an image from url and saves it to the database. | ||
| 54 | + * @param $url | ||
| 55 | + * @param string $type | ||
| 56 | + * @param bool|string $imageName | ||
| 57 | + * @return mixed | ||
| 58 | + * @throws \Exception | ||
| 59 | + */ | ||
| 60 | + private function saveNewFromUrl($url, $type, $imageName = false) | ||
| 61 | + { | ||
| 62 | + $imageName = $imageName ? $imageName : basename($url); | ||
| 63 | + $imageData = file_get_contents($url); | ||
| 64 | + if($imageData === false) throw new \Exception('Cannot get image from ' . $url); | ||
| 65 | + return $this->saveNew($imageName, $imageData, $type); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + /** | ||
| 69 | + * Saves a new image | ||
| 70 | + * @param string $imageName | ||
| 71 | + * @param string $imageData | ||
| 72 | + * @param string $type | ||
| 73 | + * @return Image | ||
| 74 | + */ | ||
| 75 | + private function saveNew($imageName, $imageData, $type) | ||
| 38 | { | 76 | { |
| 39 | $storage = $this->getStorage(); | 77 | $storage = $this->getStorage(); |
| 40 | $secureUploads = Setting::get('app-secure-images'); | 78 | $secureUploads = Setting::get('app-secure-images'); |
| 41 | - $imageName = str_replace(' ', '-', $uploadedFile->getClientOriginalName()); | 79 | + $imageName = str_replace(' ', '-', $imageName); |
| 42 | 80 | ||
| 43 | if ($secureUploads) $imageName = str_random(16) . '-' . $imageName; | 81 | if ($secureUploads) $imageName = str_random(16) . '-' . $imageName; |
| 44 | 82 | ||
| ... | @@ -48,10 +86,10 @@ class ImageService | ... | @@ -48,10 +86,10 @@ class ImageService |
| 48 | } | 86 | } |
| 49 | $fullPath = $imagePath . $imageName; | 87 | $fullPath = $imagePath . $imageName; |
| 50 | 88 | ||
| 51 | - $storage->put($fullPath, file_get_contents($uploadedFile->getRealPath())); | 89 | + $storage->put($fullPath, $imageData); |
| 52 | 90 | ||
| 53 | $userId = auth()->user()->id; | 91 | $userId = auth()->user()->id; |
| 54 | - $image = $image->forceCreate([ | 92 | + $image = Image::forceCreate([ |
| 55 | 'name' => $imageName, | 93 | 'name' => $imageName, |
| 56 | 'path' => $fullPath, | 94 | 'path' => $fullPath, |
| 57 | 'url' => $this->getPublicUrl($fullPath), | 95 | 'url' => $this->getPublicUrl($fullPath), |
| ... | @@ -138,6 +176,26 @@ class ImageService | ... | @@ -138,6 +176,26 @@ class ImageService |
| 138 | } | 176 | } |
| 139 | 177 | ||
| 140 | /** | 178 | /** |
| 179 | + * Save a gravatar image and set a the profile image for a user. | ||
| 180 | + * @param User $user | ||
| 181 | + * @param int $size | ||
| 182 | + * @return mixed | ||
| 183 | + */ | ||
| 184 | + public function saveUserGravatar(User $user, $size = 500) | ||
| 185 | + { | ||
| 186 | + if (!env('USE_GRAVATAR', false)) return false; | ||
| 187 | + $emailHash = md5(strtolower(trim($user->email))); | ||
| 188 | + $url = 'http://www.gravatar.com/avatar/' . $emailHash . '?s=' . $size . '&d=identicon'; | ||
| 189 | + $imageName = str_replace(' ', '-', $user->name . '-gravatar.png'); | ||
| 190 | + $image = $this->saveNewFromUrl($url, 'user', $imageName); | ||
| 191 | + $image->created_by = $user->id; | ||
| 192 | + $image->save(); | ||
| 193 | + $user->avatar()->associate($image); | ||
| 194 | + $user->save(); | ||
| 195 | + return $image; | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + /** | ||
| 141 | * Get the storage that will be used for storing images. | 199 | * Get the storage that will be used for storing images. |
| 142 | * @return FileSystemInstance | 200 | * @return FileSystemInstance |
| 143 | */ | 201 | */ | ... | ... |
| ... | @@ -24,7 +24,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon | ... | @@ -24,7 +24,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon |
| 24 | * | 24 | * |
| 25 | * @var array | 25 | * @var array |
| 26 | */ | 26 | */ |
| 27 | - protected $fillable = ['name', 'email', 'password']; | 27 | + protected $fillable = ['name', 'email', 'password', 'image_id']; |
| 28 | 28 | ||
| 29 | /** | 29 | /** |
| 30 | * The attributes excluded from the model's JSON form. | 30 | * The attributes excluded from the model's JSON form. |
| ... | @@ -145,8 +145,17 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon | ... | @@ -145,8 +145,17 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon |
| 145 | */ | 145 | */ |
| 146 | public function getAvatar($size = 50) | 146 | public function getAvatar($size = 50) |
| 147 | { | 147 | { |
| 148 | - $emailHash = md5(strtolower(trim($this->email))); | 148 | + if ($this->image_id === 0 || $this->image_id === null) return '/user_avatar.png'; |
| 149 | - return '//www.gravatar.com/avatar/' . $emailHash . '?s=' . $size . '&d=identicon'; | 149 | + return $this->avatar->getThumb($size, $size, true); |
| 150 | + } | ||
| 151 | + | ||
| 152 | + /** | ||
| 153 | + * Get the avatar for the user. | ||
| 154 | + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo | ||
| 155 | + */ | ||
| 156 | + public function avatar() | ||
| 157 | + { | ||
| 158 | + return $this->belongsTo('BookStack\Image', 'image_id'); | ||
| 150 | } | 159 | } |
| 151 | 160 | ||
| 152 | /** | 161 | /** | ... | ... |
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +use Illuminate\Database\Schema\Blueprint; | ||
| 4 | +use Illuminate\Database\Migrations\Migration; | ||
| 5 | + | ||
| 6 | +class AddUserAvatars extends Migration | ||
| 7 | +{ | ||
| 8 | + /** | ||
| 9 | + * Run the migrations. | ||
| 10 | + * | ||
| 11 | + * @return void | ||
| 12 | + */ | ||
| 13 | + public function up() | ||
| 14 | + { | ||
| 15 | + Schema::table('users', function (Blueprint $table) { | ||
| 16 | + $table->integer('image_id')->default(0); | ||
| 17 | + }); | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * Reverse the migrations. | ||
| 22 | + * | ||
| 23 | + * @return void | ||
| 24 | + */ | ||
| 25 | + public function down() | ||
| 26 | + { | ||
| 27 | + Schema::table('users', function (Blueprint $table) { | ||
| 28 | + $table->dropColumn('image_id'); | ||
| 29 | + }); | ||
| 30 | + } | ||
| 31 | +} |
public/user_avatar.png
0 → 100644
7.23 KB
| ... | @@ -80,15 +80,6 @@ | ... | @@ -80,15 +80,6 @@ |
| 80 | imageType: { | 80 | imageType: { |
| 81 | type: String, | 81 | type: String, |
| 82 | required: true | 82 | required: true |
| 83 | - }, | ||
| 84 | - resizeWidth: { | ||
| 85 | - type: String | ||
| 86 | - }, | ||
| 87 | - resizeHeight: { | ||
| 88 | - type: String | ||
| 89 | - }, | ||
| 90 | - resizeCrop: { | ||
| 91 | - type: Boolean | ||
| 92 | } | 83 | } |
| 93 | }, | 84 | }, |
| 94 | 85 | ||
| ... | @@ -137,21 +128,7 @@ | ... | @@ -137,21 +128,7 @@ |
| 137 | }, | 128 | }, |
| 138 | 129 | ||
| 139 | returnCallback: function (image) { | 130 | returnCallback: function (image) { |
| 140 | - var _this = this; | 131 | + this.callback(image); |
| 141 | - var isResized = _this.resizeWidth && _this.resizeHeight; | ||
| 142 | - | ||
| 143 | - if (!isResized) { | ||
| 144 | - _this.callback(image); | ||
| 145 | - return; | ||
| 146 | - } | ||
| 147 | - | ||
| 148 | - var cropped = _this.resizeCrop ? 'true' : 'false'; | ||
| 149 | - var requestString = '/images/thumb/' + image.id + '/' + _this.resizeWidth + '/' + _this.resizeHeight + '/' + cropped; | ||
| 150 | - _this.$http.get(requestString, function(data) { | ||
| 151 | - image.thumbs.custom = data.url; | ||
| 152 | - _this.callback(image); | ||
| 153 | - }); | ||
| 154 | - | ||
| 155 | }, | 132 | }, |
| 156 | 133 | ||
| 157 | imageClick: function (image) { | 134 | imageClick: function (image) { | ... | ... |
| ... | @@ -7,31 +7,89 @@ | ... | @@ -7,31 +7,89 @@ |
| 7 | </div> | 7 | </div> |
| 8 | <button class="button" type="button" @click="showImageManager">Select Image</button> | 8 | <button class="button" type="button" @click="showImageManager">Select Image</button> |
| 9 | <br> | 9 | <br> |
| 10 | - <button class="text-button" @click="reset" type="button">Reset</button> <span class="sep">|</span> <button class="text-button neg" v-on:click="remove" type="button">Remove</button> | 10 | + <button class="text-button" @click="reset" type="button">Reset</button> <span v-show="showRemove" class="sep">|</span> <button v-show="showRemove" class="text-button neg" @click="remove" type="button">Remove</button> |
| 11 | - <input type="hidden" :name="name" :id="name" v-model="image"> | 11 | + <input type="hidden" :name="name" :id="name" v-model="value"> |
| 12 | </div> | 12 | </div> |
| 13 | </template> | 13 | </template> |
| 14 | 14 | ||
| 15 | <script> | 15 | <script> |
| 16 | module.exports = { | 16 | module.exports = { |
| 17 | - props: ['currentImage', 'name', 'imageClass', 'defaultImage'], | 17 | + props: { |
| 18 | + currentImage: { | ||
| 19 | + required: true, | ||
| 20 | + type: String | ||
| 21 | + }, | ||
| 22 | + currentId: { | ||
| 23 | + required: false, | ||
| 24 | + default: 'false', | ||
| 25 | + type: String | ||
| 26 | + }, | ||
| 27 | + name: { | ||
| 28 | + required: true, | ||
| 29 | + type: String | ||
| 30 | + }, | ||
| 31 | + defaultImage: { | ||
| 32 | + required: true, | ||
| 33 | + type: String | ||
| 34 | + }, | ||
| 35 | + imageClass: { | ||
| 36 | + required: true, | ||
| 37 | + type: String | ||
| 38 | + }, | ||
| 39 | + resizeWidth: { | ||
| 40 | + type: String | ||
| 41 | + }, | ||
| 42 | + resizeHeight: { | ||
| 43 | + type: String | ||
| 44 | + }, | ||
| 45 | + resizeCrop: { | ||
| 46 | + type: Boolean | ||
| 47 | + }, | ||
| 48 | + showRemove: { | ||
| 49 | + type: Boolean, | ||
| 50 | + default: 'true' | ||
| 51 | + } | ||
| 52 | + }, | ||
| 18 | data: function() { | 53 | data: function() { |
| 19 | return { | 54 | return { |
| 20 | - image: this.currentImage | 55 | + image: this.currentImage, |
| 56 | + value: false | ||
| 21 | } | 57 | } |
| 22 | }, | 58 | }, |
| 59 | + compiled: function() { | ||
| 60 | + this.value = this.currentId === 'false' ? this.currentImage : this.currentId; | ||
| 61 | + }, | ||
| 23 | methods: { | 62 | methods: { |
| 63 | + setCurrentValue: function(imageModel, imageUrl) { | ||
| 64 | + this.image = imageUrl; | ||
| 65 | + this.value = this.currentId === 'false' ? imageUrl : imageModel.id; | ||
| 66 | + }, | ||
| 24 | showImageManager: function(e) { | 67 | showImageManager: function(e) { |
| 25 | var _this = this; | 68 | var _this = this; |
| 26 | ImageManager.show(function(image) { | 69 | ImageManager.show(function(image) { |
| 27 | - _this.image = image.thumbs.custom || image.url; | 70 | + _this.updateImageFromModel(image); |
| 28 | }); | 71 | }); |
| 29 | }, | 72 | }, |
| 30 | reset: function() { | 73 | reset: function() { |
| 31 | - this.image = ''; | 74 | + this.setCurrentValue({id: 0}, this.defaultImage); |
| 32 | }, | 75 | }, |
| 33 | remove: function() { | 76 | remove: function() { |
| 34 | this.image = 'none'; | 77 | this.image = 'none'; |
| 78 | + }, | ||
| 79 | + updateImageFromModel: function(model) { | ||
| 80 | + var _this = this; | ||
| 81 | + var isResized = _this.resizeWidth && _this.resizeHeight; | ||
| 82 | + | ||
| 83 | + if (!isResized) { | ||
| 84 | + _this.setCurrentValue(model, model.url); | ||
| 85 | + return; | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + var cropped = _this.resizeCrop ? 'true' : 'false'; | ||
| 89 | + var requestString = '/images/thumb/' + model.id + '/' + _this.resizeWidth + '/' + _this.resizeHeight + '/' + cropped; | ||
| 90 | + _this.$http.get(requestString, function(data) { | ||
| 91 | + _this.setCurrentValue(model, data.url); | ||
| 92 | + }); | ||
| 35 | } | 93 | } |
| 36 | } | 94 | } |
| 37 | }; | 95 | }; | ... | ... |
| ... | @@ -36,6 +36,10 @@ body.dragging, body.dragging * { | ... | @@ -36,6 +36,10 @@ body.dragging, body.dragging * { |
| 36 | width: 40px; | 36 | width: 40px; |
| 37 | height: 40px; | 37 | height: 40px; |
| 38 | } | 38 | } |
| 39 | + &.large { | ||
| 40 | + width: 80px; | ||
| 41 | + height: 80px; | ||
| 42 | + } | ||
| 39 | } | 43 | } |
| 40 | 44 | ||
| 41 | // System wide notifications | 45 | // System wide notifications | ... | ... |
| ... | @@ -33,7 +33,7 @@ | ... | @@ -33,7 +33,7 @@ |
| 33 | <div class="form-group" id="logo-control"> | 33 | <div class="form-group" id="logo-control"> |
| 34 | <label for="setting-app-logo">Application Logo</label> | 34 | <label for="setting-app-logo">Application Logo</label> |
| 35 | <p class="small">This image should be 43px in height. <br>Large images will be scaled down.</p> | 35 | <p class="small">This image should be 43px in height. <br>Large images will be scaled down.</p> |
| 36 | - <image-picker current-image="{{ Setting::get('app-logo', '') }}" default-image="/logo.png" name="setting-app-logo" image-class="logo-image"></image-picker> | 36 | + <image-picker resize-height="43" resize-width="200" current-image="{{ Setting::get('app-logo', '') }}" default-image="/logo.png" name="setting-app-logo" image-class="logo-image"></image-picker> |
| 37 | </div> | 37 | </div> |
| 38 | </div> | 38 | </div> |
| 39 | </div> | 39 | </div> |
| ... | @@ -86,6 +86,6 @@ | ... | @@ -86,6 +86,6 @@ |
| 86 | 86 | ||
| 87 | </div> | 87 | </div> |
| 88 | 88 | ||
| 89 | -<image-manager image-type="system" resize-height="43" resize-width="200"></image-manager> | 89 | +<image-manager image-type="system"></image-manager> |
| 90 | 90 | ||
| 91 | @stop | 91 | @stop | ... | ... |
| ... | @@ -19,26 +19,25 @@ | ... | @@ -19,26 +19,25 @@ |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | <div class="container small"> | 21 | <div class="container small"> |
| 22 | - | 22 | + <form action="/users/{{$user->id}}" method="post"> |
| 23 | <div class="row"> | 23 | <div class="row"> |
| 24 | <div class="col-md-6"> | 24 | <div class="col-md-6"> |
| 25 | <h1>Edit {{ $user->id === $currentUser->id ? 'Profile' : 'User' }}</h1> | 25 | <h1>Edit {{ $user->id === $currentUser->id ? 'Profile' : 'User' }}</h1> |
| 26 | - <form action="/users/{{$user->id}}" method="post"> | ||
| 27 | {!! csrf_field() !!} | 26 | {!! csrf_field() !!} |
| 28 | <input type="hidden" name="_method" value="put"> | 27 | <input type="hidden" name="_method" value="put"> |
| 29 | @include('users/form', ['model' => $user]) | 28 | @include('users/form', ['model' => $user]) |
| 30 | - </form> | 29 | + |
| 31 | </div> | 30 | </div> |
| 32 | <div class="col-md-6"> | 31 | <div class="col-md-6"> |
| 33 | <h1> </h1> | 32 | <h1> </h1> |
| 34 | - <div class="shaded padded margin-top"> | 33 | + <div class="form-group" id="logo-control"> |
| 35 | - <p> | 34 | + <label for="user-avatar">User Avatar</label> |
| 36 | - <img class="avatar" src="{{ $user->getAvatar(80) }}" alt="{{ $user->name }}"> | 35 | + <p class="small">This image should be approx 256px square.</p> |
| 37 | - </p> | 36 | + <image-picker resize-height="512" resize-width="512" current-image="{{ $user->getAvatar(80) }}" current-id="{{ $user->image_id }}" default-image="/user_avatar.png" name="image_id" show-remove="false" image-class="avatar large"></image-picker> |
| 38 | - <p class="text-muted">You can change your profile picture at <a href="http://en.gravatar.com/">Gravatar</a>.</p> | ||
| 39 | </div> | 37 | </div> |
| 40 | </div> | 38 | </div> |
| 41 | </div> | 39 | </div> |
| 40 | + </form> | ||
| 42 | 41 | ||
| 43 | <hr class="margin-top large"> | 42 | <hr class="margin-top large"> |
| 44 | 43 | ||
| ... | @@ -80,5 +79,5 @@ | ... | @@ -80,5 +79,5 @@ |
| 80 | </div> | 79 | </div> |
| 81 | 80 | ||
| 82 | <p class="margin-top large"><br></p> | 81 | <p class="margin-top large"><br></p> |
| 83 | - | 82 | + <image-manager image-type="user"></image-manager> |
| 84 | @stop | 83 | @stop | ... | ... |
-
Please register or sign in to post a comment