From 9a8908b643c69451118ab76ca36e5fa0e704bd0a Mon Sep 17 00:00:00 2001 From: kondou Date: Sat, 24 Aug 2013 00:35:32 +0200 Subject: [PATCH] Use Jcrop, have inline errormsg, work on cropping, clean up, WIP --- avatar.php | 24 ++++++++++--- lib/avatar.php | 13 ++++--- lib/notsquareexception.php | 12 +++++++ lib/public/avatar.php | 4 --- settings/css/settings.css | 2 ++ settings/js/personal.js | 62 ++++++++++++++++++++++++++------- settings/personal.php | 2 ++ settings/templates/personal.php | 1 + 8 files changed, 94 insertions(+), 26 deletions(-) create mode 100644 lib/notsquareexception.php diff --git a/avatar.php b/avatar.php index a54aad3b2a..c860ad9e36 100644 --- a/avatar.php +++ b/avatar.php @@ -36,26 +36,40 @@ if ($_SERVER['REQUEST_METHOD'] === "GET") { // Select an image from own files if (isset($_POST['path'])) { - //SECURITY TODO does this fully eliminate directory traversals? $path = stripslashes($_POST['path']); $avatar = OC::$SERVERROOT.'/data/'.$user.'/files'.$path; } + + if (isset($_POST['crop'])) { + $crop = json_decode($_POST['crop'], true); + if (!isset($path)) { + // TODO get path to temporarily saved uploaded-avatar + } + $image = new \OC_Image($avatar); + $image->crop($x, $y, $w, $h); + $avatar = $image->data(); + } + // Upload a new image - elseif (!empty($_FILES)) { + if (!empty($_FILES)) { $files = $_FILES['files']; if ($files['error'][0] === 0) { $avatar = file_get_contents($files['tmp_name'][0]); unlink($files['tmp_name'][0]); + // TODO make the tmp_name reusable, if the uploaded avatar is not square } - } else { - OC_JSON::error(); } try { \OC_Avatar::set($user, $avatar); OC_JSON::success(); + } catch (\OC\NotSquareException $e) { + $tmpname = \OC_Util::generate_random_bytes(10); + // TODO Save the image temporarily here + // TODO add a cronjob that cleans up stale tmpimages + OC_JSON::error(array("data" => array("message" => "notsquare", "tmpname" => $tmpname) )); } catch (\Exception $e) { - OC_JSON::error(array("data" => array ("message" => $e->getMessage()) )); + OC_JSON::error(array("data" => array("message" => $e->getMessage()) )); } } elseif ($_SERVER['REQUEST_METHOD'] === "DELETE") { $user = OC_User::getUser(); diff --git a/lib/avatar.php b/lib/avatar.php index 86be0ea263..9ab905c852 100644 --- a/lib/avatar.php +++ b/lib/avatar.php @@ -26,7 +26,7 @@ class OC_Avatar { $ext = 'png'; } else { return false; - } + } $avatar = new OC_Image($view->file_get_contents('avatar.'.$ext)); $avatar->resize($size); @@ -38,7 +38,8 @@ class OC_Avatar { * @param $user string user to set the avatar for * @param $data mixed imagedata or path to set a new avatar * @throws Exception if the provided file is not a jpg or png image - * @throws Exception if the provided image is not valid, or not a square + * @throws Exception if the provided image is not valid + * @throws \OC\NotSquareException if the image is not square * @return true on success */ public static function set ($user, $data) { @@ -52,9 +53,13 @@ class OC_Avatar { throw new \Exception($l->t("Unknown filetype")); } - if (!( $img->valid() && ($img->height() === $img->width()) )) { + if (!$img->valid()) { $l = \OC_L10N::get('lib'); - throw new \Exception($l->t("Invalid image, or the provided image is not square")); + throw new \Excpeption($l->t("Invalid image")); + } + + if (!($img->height() === $img->width())) { + throw new \OC\NotSquareException(); } $view->unlink('avatar.jpg'); diff --git a/lib/notsquareexception.php b/lib/notsquareexception.php new file mode 100644 index 0000000000..03dba8fb25 --- /dev/null +++ b/lib/notsquareexception.php @@ -0,0 +1,12 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC; + +class NotSquareException extends \Exception { +} diff --git a/lib/public/avatar.php b/lib/public/avatar.php index 768d292346..55eff57d16 100644 --- a/lib/public/avatar.php +++ b/lib/public/avatar.php @@ -12,8 +12,4 @@ class Avatar { public static function get ($user, $size = 64) { return \OC_Avatar::get($user, $size); } - - public static function getMode () { - return \OC_Avatar::getMode(); - } } diff --git a/settings/css/settings.css b/settings/css/settings.css index e6ced0e375..a2c3eaf626 100644 --- a/settings/css/settings.css +++ b/settings/css/settings.css @@ -21,6 +21,8 @@ input#openid, input#webdav { width:20em; } input#identity { width:20em; } #email { width: 17em; } +#avatar .warning { width: 350px; } + .msg.success{ color:#fff; background-color:#0f0; padding:3px; text-shadow:1px 1px #000; } .msg.error{ color:#fff; background-color:#f00; padding:3px; text-shadow:1px 1px #000; } diff --git a/settings/js/personal.js b/settings/js/personal.js index dd2d15052d..eaf90636d3 100644 --- a/settings/js/personal.js +++ b/settings/js/personal.js @@ -45,17 +45,57 @@ function changeDisplayName(){ } function selectAvatar (path) { - $.post(OC.filePath('', '', 'avatar.php'), {path: path}, function(data) { - if (data.status === "success") { - updateAvatar(); - } else { - OC.dialogs.alert(data.data.message, t('core', "Error")); - } - }); + $.post(OC.filePath('', '', 'avatar.php'), {path: path}, avatarResponseHandler); } function updateAvatar () { - $('#avatar img').attr('src', $('#avatar img').attr('src') + '#'); + $avatarimg = $('#avatar img'); + $avatarimg.attr('src', $avatarimg.attr('src') + '#'); +} + +function showAvatarCropper() { + OC.dialogs.message('', t('settings', 'Crop'), undefined, OCdialogs.OK_BUTTON, sendCropData); + var $dialog = $('#oc-dialog-'+(OC.dialogs.dialogs_counter-1)+'-content'); + var cropper = new Image(); + $(cropper).load(function() { + $(this).attr('id', 'cropper'); + $('#oc-dialog-'+(OC.dialogs.dialogs_counter-1)+'-content').html(this); + $(this).Jcrop({ + onChange: saveCoords, + onSelect: saveCoords, + aspectRatio: 1 + }); + }).attr('src', OC.filePath('', '', 'avatar.php')+"?user="+OC.currentUser+"&size=512&tmp="+$('#avatar').data('tmpname')); +} + +function sendCropData() { + var tmp = $('#avatar').data('tmpname'); + var cropperdata = $('#cropper').data(); + var data = { + x: cropperdata.x, + y: cropperdata.y, + w: cropperdata.w, + h: cropperdata.h + }; + $.post(OC.filePath('', '', 'avatar.php'), {tmp:tmp, crop: data}, avatarResponseHandler); +} + +function saveCoords(c) { + $('#cropper').data(c); +} + +function avatarResponseHandler(data) { + $warning = $('#avatar .warning'); + $warning.hide(); + if (data.status === "success") { + updateAvatar(); + } else if (data.data.message === "notsquare") { + $('#avatar').data('tmpname', data.data.tmpname); + showAvatarCropper(); + } else { + $warning.show(); + $warning.text(data.data.message); + } } $(document).ready(function(){ @@ -149,11 +189,7 @@ $(document).ready(function(){ var uploadparms = { done: function(e, data) { - if (data.result.status === "success") { - updateAvatar(); - } else { - OC.dialogs.alert(data.result.data.message, t('core', "Error")); - } + avatarResponseHandler(data.result); } }; diff --git a/settings/personal.php b/settings/personal.php index d109d33e4b..33c78c0467 100644 --- a/settings/personal.php +++ b/settings/personal.php @@ -16,6 +16,8 @@ OC_Util::addStyle( 'settings', 'settings' ); OC_Util::addScript( '3rdparty', 'chosen/chosen.jquery.min' ); OC_Util::addStyle( '3rdparty', 'chosen' ); \OC_Util::addScript('files', 'jquery.fileupload'); +\OC_Util::addScript('3rdparty/Jcrop', 'jquery.Jcrop.min'); +\OC_Util::addStyle('3rdparty/Jcrop', 'jquery.Jcrop.min'); OC_App::setActiveNavigationEntry( 'personal' ); $storageInfo=OC_Helper::getStorageInfo(); diff --git a/settings/templates/personal.php b/settings/templates/personal.php index 7cd5361a92..5db28779b5 100644 --- a/settings/templates/personal.php +++ b/settings/templates/personal.php @@ -88,6 +88,7 @@ if($_['passwordChangeSupported']) { t('Profile Image')); ?>
t('Has to be square and either PNG or JPG')); ?>
+
t('Upload new')); ?>
t('Select new from files')); ?>