summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorBernhard Posselt <Raydiation@users.noreply.github.com>2013-09-14 16:00:36 -0700
committerBernhard Posselt <Raydiation@users.noreply.github.com>2013-09-14 16:00:36 -0700
commita58e176852d80dd23b9346b4f8bd676e9ca4d8ed (patch)
tree3f06e0ab511159221e915a6fdce8393b6192bfdb /core
parenta0c2c2473a975893d590e779433091a3f7d6abb2 (diff)
parent86143beb6ae264e31e806dd195a04e5ed6f9f2d1 (diff)
downloadnextcloud-server-a58e176852d80dd23b9346b4f8bd676e9ca4d8ed.tar.gz
nextcloud-server-a58e176852d80dd23b9346b4f8bd676e9ca4d8ed.zip
Merge pull request #4506 from owncloud/oc_avatars
OC Avatars
Diffstat (limited to 'core')
-rw-r--r--core/avatar/controller.php158
-rw-r--r--core/css/styles.css20
-rw-r--r--core/js/avatar.js9
-rw-r--r--core/js/jquery.avatar.js83
-rw-r--r--core/routes.php17
-rw-r--r--core/templates/layout.user.php3
6 files changed, 288 insertions, 2 deletions
diff --git a/core/avatar/controller.php b/core/avatar/controller.php
new file mode 100644
index 00000000000..9f7c0517c4a
--- /dev/null
+++ b/core/avatar/controller.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()) ));
+ }
+ }
+}
diff --git a/core/css/styles.css b/core/css/styles.css
index bf78af15af5..dcdeda8a9c9 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 {
+ text-shadow: none;
+ float: left;
+ display: inline-block;
+}
/* INPUTS */
input[type="text"], input[type="password"], input[type="search"], input[type="number"], input[type="email"], input[type="url"],
@@ -583,8 +588,18 @@ label.infield { cursor:text !important; top:1.05em; left:.85em; }
/* USER MENU */
-#settings { float:right; margin-top:7px; color:#bbb; text-shadow:0 -1px 0 #000; }
-#expand { padding:15px; cursor:pointer; font-weight:bold; }
+#settings {
+ float: right;
+ margin-top: 7px;
+ margin-left: 10px;
+ color: #bbb;
+ text-shadow: 0 -1px 0 #000;
+}
+#expand {
+ padding: 15px 15px 15px 5px;
+ cursor: pointer;
+ font-weight: bold;
+}
#expand:hover, #expand:focus, #expand:active { color:#fff; }
#expand img { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; filter:alpha(opacity=70); opacity:.7; margin-bottom:-2px; }
#expand:hover img, #expand:focus img, #expand:active img { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; filter:alpha(opacity=100); opacity:1; }
@@ -624,6 +639,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..410182f01bf
--- /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..f1382fd7d2d
--- /dev/null
+++ b/core/js/jquery.avatar.js
@@ -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));
diff --git a/core/routes.php b/core/routes.php
index d8c2d03236f..57e25c0f1f7 100644
--- a/core/routes.php
+++ b/core/routes.php
@@ -57,6 +57,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..71bec11d219 100644
--- a/core/templates/layout.user.php
+++ b/core/templates/layout.user.php
@@ -49,6 +49,9 @@
<span id="expand" tabindex="0" role="link">
<span id="expandDisplayName"><?php p(trim($_['user_displayname']) != '' ? $_['user_displayname'] : $_['user_uid']) ?></span>
<img class="svg" src="<?php print_unescaped(image_path('', 'actions/caret.svg')); ?>" />
+ <?php if ($_['enableAvatars']): ?>
+ <div class="avatardiv"></div>
+ <?php endif; ?>
</span>
<div id="expanddiv">
<?php foreach($_['settingsnavigation'] as $entry):?>