20 changed files with 578 additions and 2 deletions
-
3config/config.sample.php
-
158core/avatar/controller.php
-
20core/css/styles.css
-
9core/js/avatar.js
-
83core/js/jquery.avatar.js
-
17core/routes.php
-
3core/templates/layout.user.php
-
89lib/avatar.php
-
8lib/base.php
-
1lib/installer.php
-
12lib/notsquareexception.php
-
1lib/templatelayout.php
-
4settings/css/settings.css
-
112settings/js/personal.js
-
6settings/personal.php
-
21settings/templates/personal.php
-
6settings/templates/users.php
-
1settings/users.php
-
BINtests/data/testavatar.png
-
26tests/lib/avatar.php
@ -0,0 +1,158 @@ |
|||
<?php |
|||
/** |
|||
* Copyright (c) 2013 Christopher Schäpers <christopher@schaepers.it> |
|||
* This file is licensed under the Affero General Public License version 3 or |
|||
* later. |
|||
* See the COPYING-README file. |
|||
*/ |
|||
|
|||
namespace OC\Core\Avatar; |
|||
|
|||
class Controller { |
|||
public static function getAvatar($args) { |
|||
\OC_JSON::checkLoggedIn(); |
|||
\OC_JSON::callCheck(); |
|||
|
|||
$user = stripslashes($args['user']); |
|||
$size = (int)$args['size']; |
|||
if ($size > 2048) { |
|||
$size = 2048; |
|||
} |
|||
// Undefined size
|
|||
elseif ($size === 0) { |
|||
$size = 64; |
|||
} |
|||
|
|||
$avatar = new \OC_Avatar($user); |
|||
$image = $avatar->get($size); |
|||
|
|||
\OC_Response::disableCaching(); |
|||
\OC_Response::setLastModifiedHeader(time()); |
|||
if ($image instanceof \OC_Image) { |
|||
\OC_Response::setETagHeader(crc32($image->data())); |
|||
$image->show(); |
|||
} else { |
|||
// Signalizes $.avatar() to display a defaultavatar
|
|||
\OC_JSON::success(); |
|||
} |
|||
} |
|||
|
|||
public static function postAvatar($args) { |
|||
\OC_JSON::checkLoggedIn(); |
|||
\OC_JSON::callCheck(); |
|||
|
|||
$user = \OC_User::getUser(); |
|||
|
|||
if (isset($_POST['path'])) { |
|||
$path = stripslashes($_POST['path']); |
|||
$view = new \OC\Files\View('/'.$user.'/files'); |
|||
$newAvatar = $view->file_get_contents($path); |
|||
} elseif (!empty($_FILES)) { |
|||
$files = $_FILES['files']; |
|||
if ( |
|||
$files['error'][0] === 0 && |
|||
is_uploaded_file($files['tmp_name'][0]) && |
|||
!\OC\Files\Filesystem::isFileBlacklisted($files['tmp_name'][0]) |
|||
) { |
|||
$newAvatar = file_get_contents($files['tmp_name'][0]); |
|||
unlink($files['tmp_name'][0]); |
|||
} |
|||
} else { |
|||
$l = new \OC_L10n('core'); |
|||
\OC_JSON::error(array("data" => array("message" => $l->t("No image or file provided")) )); |
|||
return; |
|||
} |
|||
|
|||
try { |
|||
$avatar = new \OC_Avatar($user); |
|||
$avatar->set($newAvatar); |
|||
\OC_JSON::success(); |
|||
} catch (\OC\NotSquareException $e) { |
|||
$image = new \OC_Image($newAvatar); |
|||
|
|||
if ($image->valid()) { |
|||
\OC_Cache::set('tmpavatar', $image->data(), 7200); |
|||
\OC_JSON::error(array("data" => "notsquare")); |
|||
} else { |
|||
$l = new \OC_L10n('core'); |
|||
|
|||
$mimeType = $image->mimeType(); |
|||
if ($mimeType !== 'image/jpeg' && $mimeType !== 'image/png') { |
|||
\OC_JSON::error(array("data" => array("message" => $l->t("Unknown filetype")) )); |
|||
} |
|||
|
|||
if (!$image->valid()) { |
|||
\OC_JSON::error(array("data" => array("message" => $l->t("Invalid image")) )); |
|||
} |
|||
} |
|||
} catch (\Exception $e) { |
|||
\OC_JSON::error(array("data" => array("message" => $e->getMessage()) )); |
|||
} |
|||
} |
|||
|
|||
public static function deleteAvatar($args) { |
|||
\OC_JSON::checkLoggedIn(); |
|||
\OC_JSON::callCheck(); |
|||
|
|||
$user = \OC_User::getUser(); |
|||
|
|||
try { |
|||
$avatar = new \OC_Avatar($user); |
|||
$avatar->remove(); |
|||
\OC_JSON::success(); |
|||
} catch (\Exception $e) { |
|||
\OC_JSON::error(array("data" => array("message" => $e->getMessage()) )); |
|||
} |
|||
} |
|||
|
|||
public static function getTmpAvatar($args) { |
|||
\OC_JSON::checkLoggedIn(); |
|||
\OC_JSON::callCheck(); |
|||
|
|||
$tmpavatar = \OC_Cache::get('tmpavatar'); |
|||
if (is_null($tmpavatar)) { |
|||
$l = new \OC_L10n('core'); |
|||
\OC_JSON::error(array("data" => array("message" => $l->t("No temporary profile picture available, try again")) )); |
|||
return; |
|||
} |
|||
|
|||
$image = new \OC_Image($tmpavatar); |
|||
\OC_Response::disableCaching(); |
|||
\OC_Response::setLastModifiedHeader(time()); |
|||
\OC_Response::setETagHeader(crc32($image->data())); |
|||
$image->show(); |
|||
} |
|||
|
|||
public static function postCroppedAvatar($args) { |
|||
\OC_JSON::checkLoggedIn(); |
|||
\OC_JSON::callCheck(); |
|||
|
|||
$user = \OC_User::getUser(); |
|||
if (isset($_POST['crop'])) { |
|||
$crop = $_POST['crop']; |
|||
} else { |
|||
$l = new \OC_L10n('core'); |
|||
\OC_JSON::error(array("data" => array("message" => $l->t("No crop data provided")) )); |
|||
return; |
|||
} |
|||
|
|||
$tmpavatar = \OC_Cache::get('tmpavatar'); |
|||
if (is_null($tmpavatar)) { |
|||
$l = new \OC_L10n('core'); |
|||
\OC_JSON::error(array("data" => array("message" => $l->t("No temporary profile picture available, try again")) )); |
|||
return; |
|||
} |
|||
|
|||
$image = new \OC_Image($tmpavatar); |
|||
$image->crop($crop['x'], $crop['y'], $crop['w'], $crop['h']); |
|||
try { |
|||
$avatar = new \OC_Avatar($user); |
|||
$avatar->set($image->data()); |
|||
// Clean up
|
|||
\OC_Cache::remove('tmpavatar'); |
|||
\OC_JSON::success(); |
|||
} catch (\Exception $e) { |
|||
\OC_JSON::error(array("data" => array("message" => $e->getMessage()) )); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
$(document).ready(function(){ |
|||
$('#header .avatardiv').avatar(OC.currentUser, 32); |
|||
// Personal settings
|
|||
$('#avatar .avatardiv').avatar(OC.currentUser, 128); |
|||
// User settings
|
|||
$.each($('td.avatar .avatardiv'), function(i, element) { |
|||
$(element).avatar($(element).parent().parent().data('uid'), 32); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,83 @@ |
|||
/** |
|||
* Copyright (c) 2013 Christopher Schäpers <christopher@schaepers.it> |
|||
* This file is licensed under the Affero General Public License version 3 or |
|||
* later. |
|||
* See the COPYING-README file. |
|||
*/ |
|||
|
|||
/** |
|||
* This plugin inserts the right avatar for the user, depending on, whether a |
|||
* custom avatar is uploaded - which it uses then - or not, and display a |
|||
* placeholder with the first letter of the users name instead. |
|||
* For this it queries the core_avatar_get route, thus this plugin is fit very |
|||
* tightly for owncloud, and it may not work anywhere else. |
|||
* |
|||
* You may use this on any <div></div> |
|||
* Here I'm using <div class="avatardiv"></div> as an example. |
|||
* |
|||
* There are 4 ways to call this: |
|||
* |
|||
* 1. $('.avatardiv').avatar('jdoe', 128); |
|||
* This will make the div to jdoe's fitting avatar, with a size of 128px. |
|||
* |
|||
* 2. $('.avatardiv').avatar('jdoe'); |
|||
* This will make the div to jdoe's fitting avatar. If the div aready has a |
|||
* height, it will be used for the avatars size. Otherwise this plugin will |
|||
* search for 'size' DOM data, to use for avatar size. If neither are available |
|||
* it will default to 64px. |
|||
* |
|||
* 3. $('.avatardiv').avatar(); |
|||
* This will search the DOM for 'user' data, to use as the username. If there |
|||
* is no username available it will default to a placeholder with the value of |
|||
* "x". The size will be determined the same way, as the second example. |
|||
* |
|||
* 4. $('.avatardiv').avatar('jdoe', 128, true); |
|||
* This will behave like the first example, except it will also append random |
|||
* hashes to the custom avatar images, to force image reloading in IE8. |
|||
*/ |
|||
|
|||
(function ($) { |
|||
$.fn.avatar = function(user, size, ie8fix) { |
|||
if (typeof(size) === 'undefined') { |
|||
if (this.height() > 0) { |
|||
size = this.height(); |
|||
} else if (this.data('size') > 0) { |
|||
size = this.data('size'); |
|||
} else { |
|||
size = 64; |
|||
} |
|||
} |
|||
|
|||
this.height(size); |
|||
this.width(size); |
|||
|
|||
if (typeof(user) === 'undefined') { |
|||
if (typeof(this.data('user')) !== 'undefined') { |
|||
user = this.data('user'); |
|||
} else { |
|||
this.placeholder('x'); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
// sanitize
|
|||
user = user.replace(/\//g,''); |
|||
|
|||
var $div = this; |
|||
|
|||
OC.Router.registerLoadedCallback(function() { |
|||
var url = OC.Router.generate('core_avatar_get', {user: user, size: size})+'?requesttoken='+oc_requesttoken; |
|||
$.get(url, function(result) { |
|||
if (typeof(result) === 'object') { |
|||
$div.placeholder(user); |
|||
} else { |
|||
if (ie8fix === true) { |
|||
$div.html('<img src="'+url+'#'+Math.floor(Math.random()*1000)+'">'); |
|||
} else { |
|||
$div.html('<img src="'+url+'">'); |
|||
} |
|||
} |
|||
}); |
|||
}); |
|||
}; |
|||
}(jQuery)); |
|||
@ -0,0 +1,89 @@ |
|||
<?php |
|||
/** |
|||
* Copyright (c) 2013 Christopher Schäpers <christopher@schaepers.it> |
|||
* This file is licensed under the Affero General Public License version 3 or |
|||
* later. |
|||
* See the COPYING-README file. |
|||
*/ |
|||
|
|||
/** |
|||
* This class gets and sets users avatars. |
|||
*/ |
|||
|
|||
class OC_Avatar { |
|||
|
|||
private $view; |
|||
|
|||
/** |
|||
* @brief constructor |
|||
* @param $user string user to do avatar-management with |
|||
*/ |
|||
public function __construct ($user) { |
|||
$this->view = new \OC\Files\View('/'.$user); |
|||
} |
|||
|
|||
/** |
|||
* @brief get the users avatar |
|||
* @param $size integer size in px of the avatar, defaults to 64 |
|||
* @return boolean|\OC_Image containing the avatar or false if there's no image |
|||
*/ |
|||
public function get ($size = 64) { |
|||
if ($this->view->file_exists('avatar.jpg')) { |
|||
$ext = 'jpg'; |
|||
} elseif ($this->view->file_exists('avatar.png')) { |
|||
$ext = 'png'; |
|||
} else { |
|||
return false; |
|||
} |
|||
|
|||
$avatar = new OC_Image(); |
|||
$avatar->loadFromData($this->view->file_get_contents('avatar.'.$ext)); |
|||
$avatar->resize($size); |
|||
return $avatar; |
|||
} |
|||
|
|||
/** |
|||
* @brief sets the users avatar |
|||
* @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 |
|||
* @throws \OC\NotSquareException if the image is not square |
|||
* @return void |
|||
*/ |
|||
public function set ($data) { |
|||
if (\OC_App::isEnabled('files_encryption')) { |
|||
$l = \OC_L10N::get('lib'); |
|||
throw new \Exception($l->t("Custom profile pictures don't work with encryption yet")); |
|||
} |
|||
|
|||
$img = new OC_Image($data); |
|||
$type = substr($img->mimeType(), -3); |
|||
if ($type === 'peg') { $type = 'jpg'; } |
|||
if ($type !== 'jpg' && $type !== 'png') { |
|||
$l = \OC_L10N::get('lib'); |
|||
throw new \Exception($l->t("Unknown filetype")); |
|||
} |
|||
|
|||
if (!$img->valid()) { |
|||
$l = \OC_L10N::get('lib'); |
|||
throw new \Exception($l->t("Invalid image")); |
|||
} |
|||
|
|||
if (!($img->height() === $img->width())) { |
|||
throw new \OC\NotSquareException(); |
|||
} |
|||
|
|||
$this->view->unlink('avatar.jpg'); |
|||
$this->view->unlink('avatar.png'); |
|||
$this->view->file_put_contents('avatar.'.$type, $data); |
|||
} |
|||
|
|||
/** |
|||
* @brief remove the users avatar |
|||
* @return void |
|||
*/ |
|||
public function remove () { |
|||
$this->view->unlink('avatar.jpg'); |
|||
$this->view->unlink('avatar.png'); |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
<?php |
|||
/** |
|||
* Copyright (c) 2013 Christopher Schäpers <christopher@schaepers.it> |
|||
* 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 { |
|||
} |
|||
|
After Width: 128 | Height: 128 | Size: 3.6 KiB |
@ -0,0 +1,26 @@ |
|||
<?php |
|||
/** |
|||
* Copyright (c) 2013 Christopher Schäpers <christopher@schaepers.it> |
|||
* This file is licensed under the Affero General Public License version 3 or |
|||
* later. |
|||
* See the COPYING-README file. |
|||
*/ |
|||
|
|||
class Test_Avatar extends PHPUnit_Framework_TestCase { |
|||
|
|||
public function testAvatar() { |
|||
$this->markTestSkipped("Setting custom avatars with encryption doesn't work yet"); |
|||
|
|||
$avatar = new \OC_Avatar(\OC_User::getUser()); |
|||
|
|||
$this->assertEquals(false, $avatar->get()); |
|||
|
|||
$expected = new OC_Image(\OC::$SERVERROOT.'/tests/data/testavatar.png'); |
|||
$avatar->set($expected->data()); |
|||
$expected->resize(64); |
|||
$this->assertEquals($expected->data(), $avatar->get()->data()); |
|||
|
|||
$avatar->remove(); |
|||
$this->assertEquals(false, $avatar->get()); |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue