summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/config.sample.php3
-rw-r--r--core/avatar/controller.php147
-rw-r--r--core/css/styles.css6
-rw-r--r--core/js/avatar.js9
-rw-r--r--core/js/jquery.avatar.js75
-rw-r--r--core/routes.php17
-rw-r--r--core/templates/layout.user.php5
-rw-r--r--lib/avatar.php86
-rw-r--r--lib/base.php8
-rw-r--r--lib/installer.php1
-rw-r--r--lib/notsquareexception.php12
-rw-r--r--lib/public/avatar.php12
-rw-r--r--settings/css/settings.css2
-rw-r--r--settings/js/personal.js96
-rw-r--r--settings/personal.php5
-rw-r--r--settings/templates/personal.php15
-rw-r--r--settings/templates/users.php6
-rw-r--r--tests/data/testavatar.pngbin0 -> 3705 bytes
-rw-r--r--tests/lib/avatar.php26
19 files changed, 531 insertions, 0 deletions
diff --git a/config/config.sample.php b/config/config.sample.php
index 0afad880c17..29085af4716 100644
--- a/config/config.sample.php
+++ b/config/config.sample.php
@@ -212,6 +212,9 @@ $CONFIG = array(
/* cl parameters for libreoffice / openoffice */
'preview_office_cl_parameters' => '',
+/* whether avatars should be enabled */
+'enable_avatars' => true,
+
// Extra SSL options to be used for configuration
'openssl' => array(
//'config' => '/absolute/location/of/openssl.cnf',
diff --git a/core/avatar/controller.php b/core/avatar/controller.php
new file mode 100644
index 00000000000..5264327b641
--- /dev/null
+++ b/core/avatar/controller.php
@@ -0,0 +1,147 @@
+<?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 OC_Core_Avatar_Controller {
+ public static function getAvatar($args) {
+ if (!\OC_User::isLoggedIn()) {
+ $l = new \OC_L10n('core');
+ header("HTTP/1.0 403 Forbidden");
+ \OC_Template::printErrorPage($l->t("Permission denied"));
+ return;
+ }
+
+ $user = stripslashes($args['user']);
+ $size = (int)$args['size'];
+ if ($size > 2048) {
+ $size = 2048;
+ }
+ // Undefined size
+ elseif ($size === 0) {
+ $size = 64;
+ }
+
+ $avatar = new \OC_Avatar();
+ $image = $avatar->get($user, $size);
+
+ \OC_Response::disableCaching();
+ \OC_Response::setLastModifiedHeader(time());
+ if ($image instanceof \OC_Image) {
+ \OC_Response::setETagHeader(crc32($image->data()));
+ $image->show();
+ } elseif ($image === false) {
+ \OC_JSON::success(array('user' => $user, 'size' => $size));
+ }
+ }
+
+ public static function postAvatar($args) {
+ $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);
+ }
+
+ if (!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]);
+ }
+ }
+
+ try {
+ $avatar = new \OC_Avatar();
+ $avatar->set($user, $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" => array("message" => "notsquare") ));
+ } else {
+ $l = new \OC_L10n('core');
+ $type = substr($image->mimeType(), -3);
+ if ($type === 'peg') { $type = 'jpg'; }
+ if ($type !== 'jpg' && $type !== 'png') {
+ \OC_JSON::error(array("data" => array("message" => $l->t("Unknown filetype")) ));
+ }
+
+ if (!$img->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) {
+ $user = OC_User::getUser();
+
+ try {
+ $avatar = new \OC_Avatar();
+ $avatar->remove($user);
+ \OC_JSON::success();
+ } catch (\Exception $e) {
+ \OC_JSON::error(array("data" => array("message" => $e->getMessage()) ));
+ }
+ }
+
+ public static function getTmpAvatar($args) {
+ $user = OC_User::getUser();
+
+ $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) {
+ $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();
+ $avatar->set($user, $image->data());
+ // Clean up
+ \OC_Cache::remove('tmpavatar');
+ \OC_JSON::success();
+ } catch (\Exception $e) {
+ \OC_JSON::error(array("data" => array("message" => $e->getMessage()) ));
+ }
+ }
+}
diff --git a/core/css/styles.css b/core/css/styles.css
index bf78af15af5..faa458dd58e 100644
--- a/core/css/styles.css
+++ b/core/css/styles.css
@@ -40,6 +40,11 @@ body { background:#fefefe; font:normal .8em/1.6em "Helvetica Neue",Helvetica,Ari
.header-right { float:right; vertical-align:middle; padding:0.5em; }
.header-right > * { vertical-align:middle; }
+header .avatardiv {
+ float:right;
+ margin-top: 6px;
+ margin-right: 6px;
+}
/* INPUTS */
input[type="text"], input[type="password"], input[type="search"], input[type="number"], input[type="email"], input[type="url"],
@@ -624,6 +629,7 @@ label.infield { cursor:text !important; top:1.05em; left:.85em; }
.hidden { display:none; }
.bold { font-weight:bold; }
.center { text-align:center; }
+.inlineblock { display: inline-block; }
#notification-container { position: fixed; top: 0px; width: 100%; text-align: center; z-index: 101; line-height: 1.2;}
#notification, #update-notification { z-index:101; background-color:#fc4; border:0; padding:0 .7em .3em; display:none; position: relative; top:0; -moz-border-radius-bottomleft:1em; -webkit-border-bottom-left-radius:1em; border-bottom-left-radius:1em; -moz-border-radius-bottomright:1em; -webkit-border-bottom-right-radius:1em; border-bottom-right-radius:1em; }
diff --git a/core/js/avatar.js b/core/js/avatar.js
new file mode 100644
index 00000000000..a731519244a
--- /dev/null
+++ b/core/js/avatar.js
@@ -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);
+ });
+});
diff --git a/core/js/jquery.avatar.js b/core/js/jquery.avatar.js
new file mode 100644
index 00000000000..dc73d8f0d91
--- /dev/null
+++ b/core/js/jquery.avatar.js
@@ -0,0 +1,75 @@
+/**
+ * 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 plugins inserts the right avatar for the user, depending on, whether
+ * he has a custom uploaded avatar, or not and show a placeholder with the
+ * first letter of the users displayname instead.
+ * For this it asks the core_avatar_get route, thus this plugin is fit very
+ * tightly fitted for owncloud. 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 3 ways to call this:
+ *
+ * 1. $('.avatardiv').avatar('jdoe', 128);
+ * This will make the div to jdoe's fitting avatar, with the 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 it 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 did.
+ */
+
+(function ($) {
+ $.fn.avatar = function(user, size) {
+ 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});
+ $.get(url, function(result) {
+ if (typeof(result) === 'object') {
+ $div.placeholder(result.user);
+ } else {
+ $div.html('<img src="'+url+'">');
+ }
+ });
+ });
+ };
+}(jQuery));
diff --git a/core/routes.php b/core/routes.php
index f0f8ce571e2..a0d06bf807e 100644
--- a/core/routes.php
+++ b/core/routes.php
@@ -58,6 +58,23 @@ $this->create('core_lostpassword_reset_password', '/lostpassword/reset/{token}/{
->post()
->action('OC_Core_LostPassword_Controller', 'resetPassword');
+// Avatar routes
+$this->create('core_avatar_get_tmp', '/avatar/tmp')
+ ->get()
+ ->action('OC_Core_Avatar_Controller', 'getTmpAvatar');
+$this->create('core_avatar_get', '/avatar/{user}/{size}')
+ ->get()
+ ->action('OC_Core_Avatar_Controller', 'getAvatar');
+$this->create('core_avatar_post', '/avatar/')
+ ->post()
+ ->action('OC_Core_Avatar_Controller', 'postAvatar');
+$this->create('core_avatar_delete', '/avatar/')
+ ->delete()
+ ->action('OC_Core_Avatar_Controller', 'deleteAvatar');
+$this->create('core_avatar_post_cropped', '/avatar/cropped')
+ ->post()
+ ->action('OC_Core_Avatar_Controller', 'postCroppedAvatar');
+
// Not specifically routed
$this->create('app_css', '/apps/{app}/{file}')
->requirements(array('file' => '.*.css'))
diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php
index 1e0f4a75c3c..3a46680c3fc 100644
--- a/core/templates/layout.user.php
+++ b/core/templates/layout.user.php
@@ -45,6 +45,11 @@
<a href="<?php print_unescaped(link_to('', 'index.php')); ?>" title="" id="owncloud"><img class="svg"
src="<?php print_unescaped(image_path('', 'logo-wide.svg')); ?>" alt="<?php p($theme->getName()); ?>" /></a>
<div id="logo-claim" style="display:none;"><?php p($theme->getLogoClaim()); ?></div>
+
+ <?php if (\OC_Config::getValue('enable_avatars', true) === true): ?>
+ <div class="avatardiv"></div>
+ <?php endif; ?>
+
<ul id="settings" class="svg">
<span id="expand" tabindex="0" role="link">
<span id="expandDisplayName"><?php p(trim($_['user_displayname']) != '' ? $_['user_displayname'] : $_['user_uid']) ?></span>
diff --git a/lib/avatar.php b/lib/avatar.php
new file mode 100644
index 00000000000..9b2a7fe07cf
--- /dev/null
+++ b/lib/avatar.php
@@ -0,0 +1,86 @@
+<?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 {
+ /**
+ * @brief get the users avatar
+ * @param $user string which user to get the avatar for
+ * @param $size integer size in px of the avatar, defaults to 64
+ * @return mixed \OC_Image containing the avatar or false if there's no image
+ */
+ public function get ($user, $size = 64) {
+ $view = new \OC\Files\View('/'.$user);
+
+ if ($view->file_exists('avatar.jpg')) {
+ $ext = 'jpg';
+ } elseif ($view->file_exists('avatar.png')) {
+ $ext = 'png';
+ } else {
+ return false;
+ }
+
+ $avatar = new OC_Image();
+ $avatar->loadFromData($view->file_get_contents('avatar.'.$ext));
+ $avatar->resize($size);
+ return $avatar;
+ }
+
+ /**
+ * @brief sets the users 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
+ * @throws \OC\NotSquareException if the image is not square
+ * @return void
+ */
+ public function set ($user, $data) {
+ if (\OC_Appconfig::getValue('files_encryption', 'enabled') === "yes") {
+ $l = \OC_L10N::get('lib');
+ throw new \Exception($l->t("Custom profile pictures don't work with encryption yet"));
+ }
+
+ $view = new \OC\Files\View('/'.$user);
+
+ $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();
+ }
+
+ $view->unlink('avatar.jpg');
+ $view->unlink('avatar.png');
+ $view->file_put_contents('avatar.'.$type, $data);
+ }
+
+ /**
+ * @brief remove the users avatar
+ * @param $user string user to delete the avatar from
+ * @return void
+ */
+ public function remove ($user) {
+ $view = new \OC\Files\View('/'.$user);
+ $view->unlink('avatar.jpg');
+ $view->unlink('avatar.png');
+ }
+}
diff --git a/lib/base.php b/lib/base.php
index b5c12a683ff..b66e58f54b4 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -266,6 +266,14 @@ class OC {
OC_Util::addScript('router');
OC_Util::addScript("oc-requesttoken");
+ // avatars
+ if (\OC_Config::getValue('enable_avatars', true) === true) {
+ \OC_Util::addScript('placeholder');
+ \OC_Util::addScript('3rdparty', 'md5/md5.min');
+ \OC_Util::addScript('jquery.avatar');
+ \OC_Util::addScript('avatar');
+ }
+
OC_Util::addStyle("styles");
OC_Util::addStyle("apps");
OC_Util::addStyle("fixes");
diff --git a/lib/installer.php b/lib/installer.php
index b9684eaeea0..a1d2173e22c 100644
--- a/lib/installer.php
+++ b/lib/installer.php
@@ -426,6 +426,7 @@ class OC_Installer{
'OC_API::',
'OC_App::',
'OC_AppConfig::',
+ 'OC_Avatar',
'OC_BackgroundJob::',
'OC_Config::',
'OC_DB::',
diff --git a/lib/notsquareexception.php b/lib/notsquareexception.php
new file mode 100644
index 00000000000..03dba8fb25f
--- /dev/null
+++ b/lib/notsquareexception.php
@@ -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 {
+}
diff --git a/lib/public/avatar.php b/lib/public/avatar.php
new file mode 100644
index 00000000000..6da8e83a9af
--- /dev/null
+++ b/lib/public/avatar.php
@@ -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 OCP;
+
+class Avatar extends \OC_Avatar {
+}
diff --git a/settings/css/settings.css b/settings/css/settings.css
index d5ffe448482..7b147d5b960 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 8ad26c086b5..d9b6836568e 100644
--- a/settings/js/personal.js
+++ b/settings/js/personal.js
@@ -34,6 +34,7 @@ function changeDisplayName(){
$('#oldDisplayName').text($('#displayName').val());
// update displayName on the top right expand button
$('#expandDisplayName').text($('#displayName').val());
+ updateAvatar();
}
else{
$('#newdisplayname').val(data.data.displayName);
@@ -44,6 +45,76 @@ function changeDisplayName(){
}
}
+function selectAvatar (path) {
+ $.post(OC.Router.generate('core_avatar_post'), {path: path}, avatarResponseHandler);
+}
+
+function updateAvatar () {
+ $('header .avatardiv').avatar(OC.currentUser, 32);
+ $('#avatar .avatardiv').avatar(OC.currentUser, 128);
+}
+
+function showAvatarCropper() {
+ var $dlg = $('<div class="hidden" id="cropperbox" title="'+t('settings', 'Crop')+'"><img id="cropper" src="'+OC.Router.generate('core_avatar_get_tmp')+'"></div>');
+ $('body').append($dlg);
+
+ $cropperbox = $('#cropperbox');
+ $cropper = $('#cropper');
+
+ $cropper.on('load', function() {
+ $cropperbox.show();
+
+ $cropper.Jcrop({
+ onChange: saveCoords,
+ onSelect: saveCoords,
+ aspectRatio: 1,
+ boxHeight: 500,
+ boxWidth: 500,
+ setSelect: [0, 0, 300, 300]
+ });
+
+ $cropperbox.ocdialog({
+ buttons: [{
+ text: t('settings', 'Crop'),
+ click: sendCropData,
+ defaultButton: true
+ }],
+ close: function(){
+ $(this).remove();
+ }
+ });
+ });
+}
+
+function sendCropData() {
+ var cropperdata = $('#cropper').data();
+ var data = {
+ x: cropperdata.x,
+ y: cropperdata.y,
+ w: cropperdata.w,
+ h: cropperdata.h
+ };
+ $('#cropperbox').remove();
+ $.post(OC.Router.generate('core_avatar_post_cropped'), {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") {
+ showAvatarCropper();
+ } else {
+ $warning.show();
+ $warning.text(data.data.message);
+ }
+}
+
$(document).ready(function(){
$("#passwordbutton").click( function(){
if ($('#pass1').val() !== '' && $('#pass2').val() !== '') {
@@ -128,6 +199,31 @@ $(document).ready(function(){
}
});
+ var uploadparms = {
+ done: function(e, data) {
+ avatarResponseHandler(data.result);
+ }
+ };
+
+ $('#uploadavatarbutton').click(function(){
+ $('#uploadavatar').click();
+ });
+
+ $('#uploadavatar').fileupload(uploadparms);
+
+ $('#selectavatar').click(function(){
+ OC.dialogs.filepicker(t('settings', "Select a profile picture"), selectAvatar, false, "image");
+ });
+
+ $('#removeavatar').click(function(){
+ $.ajax({
+ type: 'DELETE',
+ url: OC.Router.generate('core_avatar_delete'),
+ success: function(msg) {
+ updateAvatar();
+ }
+ });
+ });
} );
OC.Encryption = {
diff --git a/settings/personal.php b/settings/personal.php
index 112eaa3c748..88e8802663d 100644
--- a/settings/personal.php
+++ b/settings/personal.php
@@ -15,6 +15,11 @@ OC_Util::addScript( 'settings', 'personal' );
OC_Util::addStyle( 'settings', 'settings' );
OC_Util::addScript( '3rdparty', 'chosen/chosen.jquery.min' );
OC_Util::addStyle( '3rdparty', 'chosen' );
+\OC_Util::addScript('files', 'jquery.fileupload');
+if (\OC_Config::getValue('enable_avatars', true) === true) {
+ \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 63e1258b958..fcef0f8a578 100644
--- a/settings/templates/personal.php
+++ b/settings/templates/personal.php
@@ -80,6 +80,21 @@ if($_['passwordChangeSupported']) {
}
?>
+<?php if (\OC_Config::getValue('enable_avatars', true) === true): ?>
+<form id="avatar" method="post" action="<?php p(\OC_Helper::linkToRoute('core_avatar_post')); ?>">
+ <fieldset class="personalblock">
+ <legend><strong><?php p($l->t('Profile picture')); ?></strong></legend>
+ <div class="avatardiv"></div><br>
+ <div class="warning hidden"></div>
+ <div class="inlineblock button" id="uploadavatarbutton"><?php p($l->t('Upload new')); ?></div>
+ <input type="file" class="hidden" name="files[]" id="uploadavatar">
+ <div class="inlineblock button" id="selectavatar"><?php p($l->t('Select new from Files')); ?></div>
+ <div class="inlineblock button" id="removeavatar"><?php p($l->t('Remove image')); ?></div><br>
+ <?php p($l->t('Either png or jpg. Ideally square but you will be able to crop it.')); ?>
+ </fieldset>
+</form>
+<?php endif; ?>
+
<form>
<fieldset class="personalblock">
<legend><strong><?php p($l->t('Language'));?></strong></legend>
diff --git a/settings/templates/users.php b/settings/templates/users.php
index 22450fdf25f..445e5ce2fd5 100644
--- a/settings/templates/users.php
+++ b/settings/templates/users.php
@@ -81,6 +81,9 @@ $_['subadmingroups'] = array_flip($items);
<table class="hascontrols" data-groups="<?php p(json_encode($allGroups));?>">
<thead>
<tr>
+ <?php if (\OC_Config::getValue('enable_avatars', true) === true): ?>
+ <th id='headerAvatar'></th>
+ <?php endif; ?>
<th id='headerName'><?php p($l->t('Username'))?></th>
<th id="headerDisplayName"><?php p($l->t( 'Display Name' )); ?></th>
<th id="headerPassword"><?php p($l->t( 'Password' )); ?></th>
@@ -96,6 +99,9 @@ $_['subadmingroups'] = array_flip($items);
<?php foreach($_["users"] as $user): ?>
<tr data-uid="<?php p($user["name"]) ?>"
data-displayName="<?php p($user["displayName"]) ?>">
+ <?php if (\OC_Config::getValue('enable_avatars', true) === true): ?>
+ <td class="avatar"><div class="avatardiv"></div></td>
+ <?php endif; ?>
<td class="name"><?php p($user["name"]); ?></td>
<td class="displayName"><span><?php p($user["displayName"]); ?></span> <img class="svg action"
src="<?php p(image_path('core', 'actions/rename.svg'))?>"
diff --git a/tests/data/testavatar.png b/tests/data/testavatar.png
new file mode 100644
index 00000000000..24770fb634f
--- /dev/null
+++ b/tests/data/testavatar.png
Binary files differ
diff --git a/tests/lib/avatar.php b/tests/lib/avatar.php
new file mode 100644
index 00000000000..027e88d726d
--- /dev/null
+++ b/tests/lib/avatar.php
@@ -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();
+
+ $this->assertEquals(false, $avatar->get(\OC_User::getUser()));
+
+ $expected = new OC_Image(\OC::$SERVERROOT.'/tests/data/testavatar.png');
+ $avatar->set(\OC_User::getUser(), $expected->data());
+ $expected->resize(64);
+ $this->assertEquals($expected->data(), $avatar->get(\OC_User::getUser())->data());
+
+ $avatar->remove(\OC_User::getUser());
+ $this->assertEquals(false, $avatar->get(\OC_User::getUser()));
+ }
+}