Added avatar image upload

This commit is contained in:
Frederic Guillot 2016-03-26 14:43:41 -04:00
parent e71f37238c
commit 820c929ab3
31 changed files with 548 additions and 115 deletions

View File

@ -0,0 +1,55 @@
<?php
namespace Kanboard\Controller;
use Kanboard\Core\ObjectStorage\ObjectStorageException;
use Kanboard\Core\Thumbnail;
/**
* Avatar File Controller
*
* @package controller
* @author Frederic Guillot
*/
class AvatarFile extends Base
{
/**
* Show Avatar image and send aggressive caching headers
*/
public function show()
{
$user_id = $this->request->getIntegerParam('user_id');
$size = $this->request->getStringParam('size', 48);
$filename = $this->avatarFile->getFilename($user_id);
$etag = md5($filename.$size);
$this->response->cache(365 * 86400, $etag);
$this->response->contentType('image/jpeg');
if ($this->request->getHeader('If-None-Match') !== '"'.$etag.'"') {
$this->render($filename, $size);
} else {
$this->response->status(304);
}
}
/**
* Render thumbnail from object storage
*
* @access private
* @param string $filename
* @param integer $size
*/
private function render($filename, $size)
{
try {
$blob = $this->objectStorage->get($filename);
Thumbnail::createFromString($blob)
->resize($size, $size)
->toOutput();
} catch (ObjectStorageException $e) {
$this->logger->error($e->getMessage());
}
}
}

View File

@ -405,4 +405,41 @@ class User extends Base
'user' => $user,
)));
}
/**
* Display avatar page
*/
public function avatar()
{
$user = $this->getUser();
$this->response->html($this->helper->layout->user('user/avatar', array(
'user' => $user,
)));
}
/**
* Upload Avatar
*/
public function uploadAvatar()
{
$user = $this->getUser();
if (! $this->avatarFile->uploadFile($user['id'], $this->request->getFileInfo('avatar'))) {
$this->flash->failure(t('Unable to upload the file.'));
}
$this->response->redirect($this->helper->url->to('user', 'avatar', array('user_id' => $user['id'])));
}
/**
* Remove Avatar image
*/
public function removeAvatar()
{
$this->checkCSRFParam();
$user = $this->getUser();
$this->avatarFile->remove($user['id']);
$this->response->redirect($this->helper->url->to('user', 'avatar', array('user_id' => $user['id'])));
}
}

View File

@ -60,6 +60,7 @@ use Pimple\Container;
* @property \Kanboard\Formatter\GroupAutoCompleteFormatter $groupAutoCompleteFormatter
* @property \Kanboard\Model\Action $action
* @property \Kanboard\Model\ActionParameter $actionParameter
* @property \Kanboard\Model\AvatarFile $avatarFile
* @property \Kanboard\Model\Board $board
* @property \Kanboard\Model\Category $category
* @property \Kanboard\Model\Color $color

View File

@ -13,6 +13,24 @@ use Kanboard\Core\Csv;
*/
class Response extends Base
{
/**
* Send headers to cache a resource
*
* @access public
* @param integer $duration
* @param string $etag
*/
public function cache($duration, $etag = '')
{
header('Pragma: cache');
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $duration) . ' GMT');
header('Cache-Control: public, max-age=' . $duration);
if ($etag) {
header('ETag: "' . $etag . '"');
}
}
/**
* Send no cache headers
*

172
app/Core/Thumbnail.php Normal file
View File

@ -0,0 +1,172 @@
<?php
namespace Kanboard\Core;
/**
* Thumbnail Generator
*
* @package core
* @author Frederic Guillot
*/
class Thumbnail
{
protected $metadata = array();
protected $srcImage;
protected $dstImage;
/**
* Create a thumbnail from a local file
*
* @static
* @access public
* @param string $filename
* @return Thumbnail
*/
public static function createFromFile($filename)
{
$self = new static();
$self->fromFile($filename);
return $self;
}
/**
* Create a thumbnail from a string
*
* @static
* @access public
* @param string $blob
* @return Thumbnail
*/
public static function createFromString($blob)
{
$self = new static();
$self->fromString($blob);
return $self;
}
/**
* Load the local image file in memory with GD
*
* @access public
* @param string $filename
* @return Thumbnail
*/
public function fromFile($filename)
{
$this->metadata = getimagesize($filename);
$this->srcImage = imagecreatefromstring(file_get_contents($filename));
return $this;
}
/**
* Load the image blob in memory with GD
*
* @access public
* @param string $blob
* @return Thumbnail
*/
public function fromString($blob)
{
if (!function_exists('getimagesizefromstring')) {
$uri = 'data://application/octet-stream;base64,' . base64_encode($blob);
$this->metadata = getimagesize($uri);
} else {
$this->metadata = getimagesizefromstring($blob);
}
$this->srcImage = imagecreatefromstring($blob);
return $this;
}
/**
* Resize the image
*
* @access public
* @param int $width
* @param int $height
* @return Thumbnail
*/
public function resize($width = 250, $height = 100)
{
$srcWidth = $this->metadata[0];
$srcHeight = $this->metadata[1];
$dstX = 0;
$dstY = 0;
if ($width == 0 && $height == 0) {
$width = 100;
$height = 100;
}
if ($width > 0 && $height == 0) {
$dstWidth = $width;
$dstHeight = floor($srcHeight * ($width / $srcWidth));
$this->dstImage = imagecreatetruecolor($dstWidth, $dstHeight);
} elseif ($width == 0 && $height > 0) {
$dstWidth = floor($srcWidth * ($height / $srcHeight));
$dstHeight = $height;
$this->dstImage = imagecreatetruecolor($dstWidth, $dstHeight);
} else {
$srcRatio = $srcWidth / $srcHeight;
$resizeRatio = $width / $height;
if ($srcRatio <= $resizeRatio) {
$dstWidth = $width;
$dstHeight = floor($srcHeight * ($width / $srcWidth));
$dstY = ($dstHeight - $height) / 2 * (-1);
} else {
$dstWidth = floor($srcWidth * ($height / $srcHeight));
$dstHeight = $height;
$dstX = ($dstWidth - $width) / 2 * (-1);
}
$this->dstImage = imagecreatetruecolor($width, $height);
}
imagecopyresampled($this->dstImage, $this->srcImage, $dstX, $dstY, 0, 0, $dstWidth, $dstHeight, $srcWidth, $srcHeight);
return $this;
}
/**
* Save the thumbnail to a local file
*
* @access public
* @param string $filename
* @return Thumbnail
*/
public function toFile($filename)
{
imagejpeg($this->dstImage, $filename);
imagedestroy($this->dstImage);
imagedestroy($this->srcImage);
return $this;
}
/**
* Return the thumbnail as a string
*
* @access public
* @return string
*/
public function toString()
{
ob_start();
imagejpeg($this->dstImage, null);
imagedestroy($this->dstImage);
imagedestroy($this->srcImage);
return ob_get_clean();
}
/**
* Output the thumbnail directly to the browser or stdout
*
* @access public
*/
public function toOutput()
{
imagejpeg($this->dstImage, null);
imagedestroy($this->dstImage);
imagedestroy($this->srcImage);
}
}

View File

@ -75,78 +75,4 @@ class Tool
return $container;
}
/**
* Generate a jpeg thumbnail from an image
*
* @static
* @access public
* @param string $src_file Source file image
* @param string $dst_file Destination file image
* @param integer $resize_width Desired image width
* @param integer $resize_height Desired image height
*/
public static function generateThumbnail($src_file, $dst_file, $resize_width = 250, $resize_height = 100)
{
$metadata = getimagesize($src_file);
$src_width = $metadata[0];
$src_height = $metadata[1];
$dst_y = 0;
$dst_x = 0;
if (empty($metadata['mime'])) {
return;
}
if ($resize_width == 0 && $resize_height == 0) {
$resize_width = 100;
$resize_height = 100;
}
if ($resize_width > 0 && $resize_height == 0) {
$dst_width = $resize_width;
$dst_height = floor($src_height * ($resize_width / $src_width));
$dst_image = imagecreatetruecolor($dst_width, $dst_height);
} elseif ($resize_width == 0 && $resize_height > 0) {
$dst_width = floor($src_width * ($resize_height / $src_height));
$dst_height = $resize_height;
$dst_image = imagecreatetruecolor($dst_width, $dst_height);
} else {
$src_ratio = $src_width / $src_height;
$resize_ratio = $resize_width / $resize_height;
if ($src_ratio <= $resize_ratio) {
$dst_width = $resize_width;
$dst_height = floor($src_height * ($resize_width / $src_width));
$dst_y = ($dst_height - $resize_height) / 2 * (-1);
} else {
$dst_width = floor($src_width * ($resize_height / $src_height));
$dst_height = $resize_height;
$dst_x = ($dst_width - $resize_width) / 2 * (-1);
}
$dst_image = imagecreatetruecolor($resize_width, $resize_height);
}
switch ($metadata['mime']) {
case 'image/jpeg':
case 'image/jpg':
$src_image = imagecreatefromjpeg($src_file);
break;
case 'image/png':
$src_image = imagecreatefrompng($src_file);
break;
case 'image/gif':
$src_image = imagecreatefromgif($src_file);
break;
default:
return;
}
imagecopyresampled($dst_image, $src_image, $dst_x, $dst_y, 0, 0, $dst_width, $dst_height, $src_width, $src_height);
imagejpeg($dst_image, $dst_file);
imagedestroy($dst_image);
}
}

View File

@ -32,23 +32,25 @@ class AvatarManager
}
/**
* Render avatar html element
* Render avatar HTML element
*
* @access public
* @param string $user_id
* @param string $username
* @param string $name
* @param string $email
* @param string $avatar_path
* @param int $size
* @return string
*/
public function render($user_id, $username, $name, $email, $size)
public function render($user_id, $username, $name, $email, $avatar_path, $size)
{
$user = array(
'id' => $user_id,
'username' => $username,
'name' => $name,
'email' => $email,
'avatar_path' => $avatar_path,
);
krsort($this->providers);
@ -80,6 +82,7 @@ class AvatarManager
'username' => '',
'name' => '?',
'email' => '',
'avatar_path' => '',
);
return $provider->render($user, $size);

View File

@ -13,6 +13,19 @@ use Kanboard\Core\Security\Role;
*/
class UserSession extends Base
{
/**
* Refresh current session if necessary
*
* @access public
* @param integer $user_id
*/
public function refresh($user_id)
{
if ($this->getId() == $user_id) {
$this->initialize($this->user->getById($user_id));
}
}
/**
* Update user session
*

View File

@ -20,16 +20,17 @@ class AvatarHelper extends Base
* @param string $username
* @param string $name
* @param string $email
* @param string $avatar_path
* @param string $css
* @param int $size
* @return string
*/
public function render($user_id, $username, $name, $email, $css = 'avatar-left', $size = 48)
public function render($user_id, $username, $name, $email, $avatar_path, $css = 'avatar-left', $size = 48)
{
if (empty($user_id) && empty($username)) {
$html = $this->avatarManager->renderDefault($size);
} else {
$html = $this->avatarManager->render($user_id, $username, $name, $email, $size);
$html = $this->avatarManager->render($user_id, $username, $name, $email, $avatar_path, $size);
}
return '<div class="avatar avatar-'.$size.' '.$css.'">'.$html.'</div>';
@ -39,26 +40,29 @@ class AvatarHelper extends Base
* Render small user avatar
*
* @access public
* @param string $user_id
* @param string $username
* @param string $name
* @param string $email
* @param string $user_id
* @param string $username
* @param string $name
* @param string $email
* @param string $avatar_path
* @param string $css
* @return string
*/
public function small($user_id, $username, $name, $email, $css = '')
public function small($user_id, $username, $name, $email, $avatar_path, $css = '')
{
return $this->render($user_id, $username, $name, $email, $css, 20);
return $this->render($user_id, $username, $name, $email, $avatar_path, $css, 20);
}
/**
* Get a small avatar for the current user
*
* @access public
* @param string $css
* @return string
*/
public function currentUserSmall($css = '')
{
$user = $this->userSession->getAll();
return $this->small($user['id'], $user['username'], $user['name'], $user['email'], $css);
return $this->small($user['id'], $user['username'], $user['name'], $user['email'], $user['avatar_path'], $css);
}
}

111
app/Model/AvatarFile.php Normal file
View File

@ -0,0 +1,111 @@
<?php
namespace Kanboard\Model;
use Exception;
/**
* Avatar File
*
* @package model
* @author Frederic Guillot
*/
class AvatarFile extends Base
{
/**
* Path prefix
*
* @var string
*/
const PATH_PREFIX = 'avatars';
/**
* Get image filename
*
* @access public
* @param integer $user_id
* @return string
*/
public function getFilename($user_id)
{
return $this->db->table(User::TABLE)->eq('id', $user_id)->findOneColumn('avatar_path');
}
/**
* Add avatar in the user profile
*
* @access public
* @param integer $user_id Foreign key
* @param string $path Path on the disk
* @return bool
*/
public function create($user_id, $path)
{
$result = $this->db->table(User::TABLE)->eq('id', $user_id)->update(array(
'avatar_path' => $path,
));
$this->userSession->refresh($user_id);
return $result;
}
/**
* Remove avatar from the user profile
*
* @access public
* @param integer $user_id Foreign key
* @return bool
*/
public function remove($user_id)
{
try {
$this->objectStorage->remove($this->getFilename($user_id));
$result = $this->db->table(User::TABLE)->eq('id', $user_id)->update(array('avatar_path' => ''));
$this->userSession->refresh($user_id);
return $result;
} catch (Exception $e) {
$this->logger->error($e->getMessage());
return false;
}
}
/**
* Upload avatar image
*
* @access public
* @param integer $user_id
* @param array $file
*/
public function uploadFile($user_id, array $file)
{
try {
if ($file['error'] == UPLOAD_ERR_OK && $file['size'] > 0) {
$destination_filename = $this->generatePath($user_id, $file['name']);
$this->objectStorage->moveUploadedFile($file['tmp_name'], $destination_filename);
$this->create($user_id, $destination_filename);
} else {
throw new Exception('File not uploaded: '.var_export($file['error'], true));
}
} catch (Exception $e) {
$this->logger->error($e->getMessage());
return false;
}
return true;
}
/**
* Generate the path for a new filename
*
* @access public
* @param integer $user_id
* @param string $filename
* @return string
*/
public function generatePath($user_id, $filename)
{
return implode(DIRECTORY_SEPARATOR, array(self::PATH_PREFIX, $user_id, hash('sha1', $filename.time())));
}
}

View File

@ -48,7 +48,8 @@ class Comment extends Base
self::TABLE.'.comment',
User::TABLE.'.username',
User::TABLE.'.name',
User::TABLE.'.email'
User::TABLE.'.email',
User::TABLE.'.avatar_path'
)
->join(User::TABLE, 'id', 'user_id')
->orderBy(self::TABLE.'.date_creation', $sorting)

View File

@ -3,6 +3,7 @@
namespace Kanboard\Model;
use Exception;
use Kanboard\Core\Thumbnail;
use Kanboard\Event\FileEvent;
use Kanboard\Core\Tool;
use Kanboard\Core\ObjectStorage\ObjectStorageException;
@ -315,15 +316,15 @@ abstract class File extends Base
*/
public function generateThumbnailFromData($destination_filename, &$data)
{
$temp_filename = tempnam(sys_get_temp_dir(), 'datafile');
$blob = Thumbnail::createFromString($data)
->resize()
->toString();
file_put_contents($temp_filename, $data);
$this->generateThumbnailFromFile($temp_filename, $destination_filename);
unlink($temp_filename);
$this->objectStorage->put($this->getThumbnailPath($destination_filename), $blob);
}
/**
* Generate thumbnail from a blob
* Generate thumbnail from a local file
*
* @access public
* @param string $uploaded_filename
@ -331,8 +332,10 @@ abstract class File extends Base
*/
public function generateThumbnailFromFile($uploaded_filename, $destination_filename)
{
$thumbnail_filename = tempnam(sys_get_temp_dir(), 'thumbnail');
Tool::generateThumbnail($uploaded_filename, $thumbnail_filename);
$this->objectStorage->moveFile($thumbnail_filename, $this->getThumbnailPath($destination_filename));
$blob = Thumbnail::createFromFile($uploaded_filename)
->resize()
->toString();
$this->objectStorage->put($this->getThumbnailPath($destination_filename), $blob);
}
}

View File

@ -88,7 +88,8 @@ class ProjectActivity extends Base
self::TABLE.'.*',
User::TABLE.'.username AS author_username',
User::TABLE.'.name AS author_name',
User::TABLE.'.email'
User::TABLE.'.email',
User::TABLE.'.avatar_path'
)
->in('project_id', $project_ids)
->join(User::TABLE, 'id', 'creator_id')
@ -117,7 +118,8 @@ class ProjectActivity extends Base
self::TABLE.'.*',
User::TABLE.'.username AS author_username',
User::TABLE.'.name AS author_name',
User::TABLE.'.email'
User::TABLE.'.email',
User::TABLE.'.avatar_path'
)
->eq('task_id', $task_id)
->join(User::TABLE, 'id', 'creator_id')

View File

@ -128,6 +128,7 @@ class TaskFinder extends Base
User::TABLE.'.username AS assignee_username',
User::TABLE.'.name AS assignee_name',
User::TABLE.'.email AS assignee_email',
User::TABLE.'.avatar_path AS assignee_avatar_path',
Category::TABLE.'.name AS category_name',
Category::TABLE.'.description AS category_description',
Column::TABLE.'.title AS column_name',

View File

@ -283,12 +283,7 @@ class User extends Base
{
$this->prepare($values);
$result = $this->db->table(self::TABLE)->eq('id', $values['id'])->update($values);
// If the user is connected refresh his session
if ($this->userSession->getId() == $values['id']) {
$this->userSession->initialize($this->getById($this->userSession->getId()));
}
$this->userSession->refresh($values['id']);
return $result;
}
@ -327,6 +322,9 @@ class User extends Base
{
return $this->db->transaction(function (Database $db) use ($user_id) {
// Remove Avatar
$this->avatarFile->remove($user_id);
// All assigned tasks are now unassigned (no foreign key)
if (! $db->table(Task::TABLE)->eq('owner_id', $user_id)->update(array('owner_id' => 0))) {
return false;

View File

@ -6,7 +6,12 @@ use PDO;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
const VERSION = 108;
const VERSION = 109;
function version_109(PDO $pdo)
{
$pdo->exec("ALTER TABLE users ADD COLUMN avatar_path VARCHAR(255)");
}
function version_108(PDO $pdo)
{

View File

@ -6,7 +6,12 @@ use PDO;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
const VERSION = 88;
const VERSION = 89;
function version_89(PDO $pdo)
{
$pdo->exec("ALTER TABLE users ADD COLUMN avatar_path VARCHAR(255)");
}
function version_88(PDO $pdo)
{

View File

@ -6,7 +6,12 @@ use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
use PDO;
const VERSION = 100;
const VERSION = 101;
function version_101(PDO $pdo)
{
$pdo->exec("ALTER TABLE users ADD COLUMN avatar_path TEXT");
}
function version_100(PDO $pdo)
{

View File

@ -125,6 +125,7 @@ class AuthenticationProvider implements ServiceProviderInterface
$acl->add('Board', 'readonly', Role::APP_PUBLIC);
$acl->add('Ical', '*', Role::APP_PUBLIC);
$acl->add('Feed', '*', Role::APP_PUBLIC);
$acl->add('AvatarFile', 'show', Role::APP_PUBLIC);
$acl->add('Config', '*', Role::APP_ADMIN);
$acl->add('Currency', '*', Role::APP_ADMIN);

View File

@ -6,6 +6,7 @@ use Pimple\Container;
use Pimple\ServiceProviderInterface;
use Kanboard\Core\User\Avatar\AvatarManager;
use Kanboard\User\Avatar\GravatarProvider;
use Kanboard\User\Avatar\AvatarFileProvider;
use Kanboard\User\Avatar\LetterAvatarProvider;
/**
@ -28,6 +29,7 @@ class AvatarProvider implements ServiceProviderInterface
$container['avatarManager'] = new AvatarManager;
$container['avatarManager']->register(new LetterAvatarProvider($container));
$container['avatarManager']->register(new GravatarProvider($container));
$container['avatarManager']->register(new AvatarFileProvider($container));
return $container;
}
}

View File

@ -24,6 +24,7 @@ class ClassProvider implements ServiceProviderInterface
'Model' => array(
'Action',
'ActionParameter',
'AvatarFile',
'Board',
'Category',
'Color',

View File

@ -12,6 +12,7 @@
$task['assignee_username'],
$task['assignee_name'],
$task['assignee_email'],
$task['assignee_avatar_path'],
'avatar-inline'
) ?>
</span>

View File

@ -1,6 +1,6 @@
<div class="comment <?= isset($preview) ? 'comment-preview' : '' ?>" id="comment-<?= $comment['id'] ?>">
<?= $this->avatar->render($comment['user_id'], $comment['username'], $comment['name'], $comment['email']) ?>
<?= $this->avatar->render($comment['user_id'], $comment['username'], $comment['name'], $comment['email'], $comment['avatar_path']) ?>
<div class="comment-title">
<?php if (! empty($comment['username'])): ?>

View File

@ -7,7 +7,8 @@
$event['creator_id'],
$event['author_username'],
$event['author_name'],
$event['email']
$event['email'],
$event['avatar_path']
) ?>
<div class="activity-content">

View File

@ -0,0 +1,20 @@
<div class="page-header">
<h2><?= t('Avatar') ?></h2>
</div>
<?= $this->avatar->render($user['id'], $user['username'], $user['name'], $user['email'], $user['avatar_path'], '') ?>
<form method="post" enctype="multipart/form-data" action="<?= $this->url->href('user', 'uploadAvatar', array('user_id' => $user['id'])) ?>">
<?= $this->form->csrf() ?>
<?= $this->form->label(t('Upload my avatar image'), 'avatar') ?>
<?= $this->form->file('avatar') ?>
<div class="form-actions">
<?php if (! empty($user['avatar_path'])): ?>
<?= $this->url->link(t('Remove my image'), 'User', 'removeAvatar', array('user_id' => $user['id']), true, 'btn btn-red') ?>
<?php endif ?>
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>
<?= $this->url->link(t('cancel'), 'user', 'show', array('user_id' => $user['id'])) ?>
</div>
</form>

View File

@ -37,6 +37,9 @@
<li <?= $this->app->checkMenuSelection('user', 'edit') ?>>
<?= $this->url->link(t('Edit profile'), 'user', 'edit', array('user_id' => $user['id'])) ?>
</li>
<li <?= $this->app->checkMenuSelection('user', 'avatar') ?>>
<?= $this->url->link(t('Avatar'), 'user', 'avatar', array('user_id' => $user['id'])) ?>
</li>
<?php endif ?>
<?php if ($user['is_ldap_user'] == 0): ?>

View File

@ -0,0 +1,42 @@
<?php
namespace Kanboard\User\Avatar;
use Kanboard\Core\Base;
use Kanboard\Core\User\Avatar\AvatarProviderInterface;
/**
* Avatar Local Image File Provider
*
* @package avatar
* @author Frederic Guillot
*/
class AvatarFileProvider extends Base implements AvatarProviderInterface
{
/**
* Render avatar html
*
* @access public
* @param array $user
* @param int $size
* @return string
*/
public function render(array $user, $size)
{
$url = $this->helper->url->href('AvatarFile', 'show', array('user_id' => $user['id'], 'size' => $size));
$title = $this->helper->text->e($user['name'] ?: $user['username']);
return '<img src="' . $url . '" alt="' . $title . '" title="' . $title . '">';
}
/**
* Determine if the provider is active
*
* @access public
* @param array $user
* @return boolean
*/
public function isActive(array $user)
{
return !empty($user['avatar_path']);
}
}

View File

@ -17,8 +17,9 @@ class GravatarProvider extends Base implements AvatarProviderInterface
* Render avatar html
*
* @access public
* @param array $user
* @param int $size
* @param array $user
* @param int $size
* @return string
*/
public function render(array $user, $size)
{

View File

@ -24,8 +24,9 @@ class LetterAvatarProvider extends Base implements AvatarProviderInterface
* Render avatar html
*
* @access public
* @param array $user
* @param int $size
* @param array $user
* @param int $size
* @return string
*/
public function render(array $user, $size)
{

View File

@ -278,7 +278,7 @@ class ProjectFileTest extends Base
$fileModel = $this
->getMockBuilder('\Kanboard\Model\ProjectFile')
->setConstructorArgs(array($this->container))
->setMethods(array('generateThumbnailFromFile'))
->setMethods(array('generateThumbnailFromData'))
->getMock();
$projectModel = new Project($this->container);
@ -288,7 +288,7 @@ class ProjectFileTest extends Base
$fileModel
->expects($this->once())
->method('generateThumbnailFromFile');
->method('generateThumbnailFromData');
$this->container['objectStorage']
->expects($this->once())

View File

@ -331,7 +331,7 @@ class TaskFileTest extends Base
$fileModel = $this
->getMockBuilder('\Kanboard\Model\TaskFile')
->setConstructorArgs(array($this->container))
->setMethods(array('generateThumbnailFromFile'))
->setMethods(array('generateThumbnailFromData'))
->getMock();
$projectModel = new Project($this->container);
@ -343,7 +343,7 @@ class TaskFileTest extends Base
$fileModel
->expects($this->once())
->method('generateThumbnailFromFile');
->method('generateThumbnailFromData');
$this->container['objectStorage']
->expects($this->once())