Added support for custom avatars
This commit is contained in:
parent
3051f37587
commit
fee19c61bc
27 changed files with 395 additions and 9 deletions
|
@ -7,6 +7,7 @@ filesPath = "./data/files/"
|
|||
logsPath = "./data/logs/{yyyy}-{mm}.log"
|
||||
mediaPath = "./public_html/media/"
|
||||
thumbnailsPath = "./public_html/thumbs/"
|
||||
avatarsPath = "./public_html/avatars/"
|
||||
title = "szurubooru"
|
||||
salt = "1A2/$_4xVa"
|
||||
|
||||
|
@ -129,6 +130,8 @@ editUserEmail.all=admin
|
|||
editUserEmailNoConfirm=admin
|
||||
editUserAccessRank=admin
|
||||
editUserName=moderator
|
||||
editUserAvatar.own=registered
|
||||
editUserAvatar.all=admin
|
||||
editUserSettings.own=registered
|
||||
editUserSettings.all=nobody
|
||||
acceptUserRegistration=moderator
|
||||
|
|
2
public_html/avatars/.gitignore
vendored
Normal file
2
public_html/avatars/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
11
public_html/media/js/user-edit.js
Normal file
11
public_html/media/js/user-edit.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
$(function()
|
||||
{
|
||||
$('.avatar-content').parents('.form-row').hide();
|
||||
$('.avatar-style').click(function()
|
||||
{
|
||||
if ($(this).val() == '2'/*custom*/)
|
||||
{
|
||||
$('.avatar-content').parents('.form-row').show();
|
||||
}
|
||||
});
|
||||
});
|
|
@ -39,6 +39,8 @@ class JobArgs
|
|||
const ARG_NEW_EMAIL = 'new-email';
|
||||
const ARG_NEW_USER_NAME = 'new-user-name';
|
||||
const ARG_NEW_PASSWORD = 'new-password';
|
||||
const ARG_NEW_AVATAR_CONTENT = 'new-avatar-content';
|
||||
const ARG_NEW_AVATAR_STYLE = 'new-avatar-style';
|
||||
const ARG_NEW_SETTINGS = 'new-settings';
|
||||
|
||||
const ARG_NEW_POST_SCORE = 'new-post-score';
|
||||
|
|
64
src/Api/Jobs/UserJobs/EditUserAvatarJob.php
Normal file
64
src/Api/Jobs/UserJobs/EditUserAvatarJob.php
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
class EditUserAvatarJob extends AbstractJob
|
||||
{
|
||||
protected $userRetriever;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->userRetriever = new UserRetriever($this);
|
||||
}
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$user = $this->userRetriever->retrieve();
|
||||
$state = $this->getArgument(JobArgs::ARG_NEW_AVATAR_STYLE);
|
||||
|
||||
if ($state == UserAvatarStyle::Custom)
|
||||
{
|
||||
$file = $this->getArgument(JobArgs::ARG_NEW_AVATAR_CONTENT);
|
||||
$user->setCustomAvatarFromPath($file->filePath);
|
||||
}
|
||||
else
|
||||
$user->setAvatarStyle(new UserAvatarStyle($state));
|
||||
|
||||
if ($this->getContext() == self::CONTEXT_NORMAL)
|
||||
UserModel::save($user);
|
||||
|
||||
Logger::log('{user} changed avatar for {subject}', [
|
||||
'user' => TextHelper::reprUser(Auth::getCurrentUser()),
|
||||
'subject' => TextHelper::reprUser($user)]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function getRequiredArguments()
|
||||
{
|
||||
return JobArgs::Conjunction(
|
||||
$this->userRetriever->getRequiredArguments(),
|
||||
JobArgs::ARG_NEW_AVATAR_STYLE,
|
||||
JobArgs::Optional(JobArgs::ARG_NEW_AVATAR_CONTENT));
|
||||
}
|
||||
|
||||
public function getRequiredMainPrivilege()
|
||||
{
|
||||
return $this->getContext() == self::CONTEXT_BATCH_ADD
|
||||
? Privilege::RegisterAccount
|
||||
: Privilege::EditUserAvatar;
|
||||
}
|
||||
|
||||
public function getRequiredSubPrivileges()
|
||||
{
|
||||
return Access::getIdentity($this->userRetriever->retrieve());
|
||||
}
|
||||
|
||||
public function isAuthenticationRequired()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isConfirmedEmailRequired()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ class EditUserJob extends AbstractJob
|
|||
$this->addSubJob(new EditUserNameJob());
|
||||
$this->addSubJob(new EditUserPasswordJob());
|
||||
$this->addSubJob(new EditUserEmailJob());
|
||||
$this->addSubJob(new EditUserAvatarJob());
|
||||
}
|
||||
|
||||
public function canEditAnything($user)
|
||||
|
|
|
@ -76,12 +76,25 @@ class UserController extends AbstractController
|
|||
JobArgs::ARG_NEW_PASSWORD => InputHelper::get('password1'),
|
||||
JobArgs::ARG_NEW_EMAIL => InputHelper::get('email'),
|
||||
JobArgs::ARG_NEW_ACCESS_RANK => InputHelper::get('access-rank'),
|
||||
Jobargs::ARG_NEW_AVATAR_STYLE => InputHelper::get('avatar-style'),
|
||||
];
|
||||
|
||||
if (!empty($_FILES['avatar-content']['name']))
|
||||
{
|
||||
$file = $_FILES['avatar-content'];
|
||||
TransferHelper::handleUploadErrors($file);
|
||||
|
||||
$args[JobArgs::ARG_NEW_AVATAR_CONTENT] = new ApiFileInput(
|
||||
$file['tmp_name'],
|
||||
$file['name']);
|
||||
}
|
||||
|
||||
$args = $this->appendUserIdentifierArgument($args, $identifier);
|
||||
|
||||
$args = array_filter($args);
|
||||
$user = Api::run(new EditUserJob(), $args);
|
||||
|
||||
Core::getContext()->transport->user = $user;
|
||||
if (Auth::getCurrentUser()->getId() == $user->getId())
|
||||
Auth::setCurrentUser($user);
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ class Privilege extends AbstractEnum implements IEnum
|
|||
const EditUserEmail = 'editUserEmail';
|
||||
const EditUserEmailNoConfirm = 'editUserEmailNoConfirm';
|
||||
const EditUserName = 'editUserName';
|
||||
const EditUserAvatar = 'editUserAvatar';
|
||||
const EditUserSettings = 'editUserSettings';
|
||||
const DeleteUser = 'deleteUser';
|
||||
const FlagUser = 'flagUser';
|
||||
|
|
44
src/Enums/UserAvatarStyle.php
Normal file
44
src/Enums/UserAvatarStyle.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
class UserAvatarStyle extends AbstractEnum implements IEnum, IValidatable
|
||||
{
|
||||
const Gravatar = 1;
|
||||
const Custom = 2;
|
||||
const None = 3;
|
||||
|
||||
private $type;
|
||||
|
||||
public function __construct($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
public function toInteger()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function toString()
|
||||
{
|
||||
switch ($this->type)
|
||||
{
|
||||
case self::None: return 'none';
|
||||
case self::Gravatar: return 'gravatar';
|
||||
case self::Custom: return 'custom';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getAll()
|
||||
{
|
||||
return array_map(function($constantName)
|
||||
{
|
||||
return new self($constantName);
|
||||
}, self::getAllConstants());
|
||||
}
|
||||
|
||||
public function validate()
|
||||
{
|
||||
if (!in_array($this->type, self::getAllConstants()))
|
||||
throw new SimpleException('Invalid user picture type "%s"', $this->type);
|
||||
}
|
||||
}
|
|
@ -391,7 +391,7 @@ final class PostEntity extends AbstractEntity implements IValidatable, ISerializ
|
|||
{
|
||||
$width = Core::getConfig()->browsing->thumbnailWidth;
|
||||
$height = Core::getConfig()->browsing->thumbnailHeight;
|
||||
$dstPath = $this->getThumbnailPath($width, $height);
|
||||
$dstPath = $this->getThumbnailPath();
|
||||
|
||||
$thumbnailGenerator = new SmartThumbnailGenerator();
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ final class UserEntity extends AbstractEntity implements IValidatable, ISerializ
|
|||
private $lastLoginDate;
|
||||
private $accessRank;
|
||||
private $banned = false;
|
||||
private $avatarStyle;
|
||||
|
||||
private $settings;
|
||||
private $_passwordChanged = false;
|
||||
|
@ -23,6 +24,7 @@ final class UserEntity extends AbstractEntity implements IValidatable, ISerializ
|
|||
{
|
||||
$this->setAccessRank(new AccessRank(AccessRank::Anonymous));
|
||||
$this->setPasswordSalt(md5(mt_rand() . uniqid()));
|
||||
$this->avatarStyle = new UserAvatarStyle(UserAvatarStyle::Gravatar);
|
||||
$this->settings = new UserSettings();
|
||||
}
|
||||
|
||||
|
@ -39,6 +41,7 @@ final class UserEntity extends AbstractEntity implements IValidatable, ISerializ
|
|||
$this->lastLoginDate = TextHelper::toIntegerOrNull($row['last_login_date']);
|
||||
$this->banned = $row['banned'];
|
||||
$this->setAccessRank(new AccessRank($row['access_rank']));
|
||||
$this->avatarStyle = new UserAvatarStyle($row['avatar_style']);
|
||||
$this->settings = new UserSettings($row['settings']);
|
||||
}
|
||||
|
||||
|
@ -61,6 +64,7 @@ final class UserEntity extends AbstractEntity implements IValidatable, ISerializ
|
|||
$this->validateAccessRank();
|
||||
$this->validateEmails();
|
||||
$this->settings->validate();
|
||||
$this->avatarStyle->validate();
|
||||
|
||||
if (empty($this->getAccessRank()))
|
||||
throw new Exception('No access rank detected');
|
||||
|
@ -276,14 +280,44 @@ final class UserEntity extends AbstractEntity implements IValidatable, ISerializ
|
|||
$this->accessRank = $accessRank;
|
||||
}
|
||||
|
||||
public function getAvatarStyle()
|
||||
{
|
||||
return $this->avatarStyle;
|
||||
}
|
||||
|
||||
public function setAvatarStyle(UserAvatarStyle $userAvatarStyle)
|
||||
{
|
||||
$this->avatarStyle = $userAvatarStyle;
|
||||
}
|
||||
|
||||
public function getAvatarUrl($size = 32)
|
||||
{
|
||||
$subject = !empty($this->getConfirmedEmail())
|
||||
? $this->getConfirmedEmail()
|
||||
: $this->passSalt . $this->getName();
|
||||
$hash = md5(strtolower(trim($subject)));
|
||||
$url = 'http://www.gravatar.com/avatar/' . $hash . '?s=' . $size . '&d=retro';
|
||||
return $url;
|
||||
switch ($this->avatarStyle->toInteger())
|
||||
{
|
||||
case UserAvatarStyle::None:
|
||||
return $this->getBlankAvatarUrl($size);
|
||||
|
||||
case UserAvatarStyle::Gravatar:
|
||||
return $this->getGravatarAvatarUrl($size);
|
||||
|
||||
case UserAvatarStyle::Custom:
|
||||
return $this->getCustomAvatarUrl($size);
|
||||
}
|
||||
}
|
||||
|
||||
public function setCustomAvatarFromPath($srcPath)
|
||||
{
|
||||
$config = Core::getConfig();
|
||||
|
||||
$mimeType = mime_content_type($srcPath);
|
||||
if (!in_array($mimeType, ['image/gif', 'image/png', 'image/jpeg']))
|
||||
throw new SimpleException('Invalid file type "%s"', $mimeType);
|
||||
|
||||
$dstPath = $this->getCustomAvatarSourcePath();
|
||||
|
||||
TransferHelper::copy($srcPath, $dstPath);
|
||||
$this->removeOldCustomAvatar();
|
||||
$this->setAvatarStyle(new UserAvatarStyle(UserAvatarStyle::Custom));
|
||||
}
|
||||
|
||||
public function getSettings()
|
||||
|
@ -351,4 +385,67 @@ final class UserEntity extends AbstractEntity implements IValidatable, ISerializ
|
|||
$stmt->setCriterion(new Sql\EqualsFunctor('uploader_id', new Sql\Binding($this->getId())));
|
||||
return (int) Database::fetchOne($stmt)['count'];
|
||||
}
|
||||
|
||||
|
||||
private function getBlankAvatarUrl($size)
|
||||
{
|
||||
return 'http://www.gravatar.com/avatar/?s=' . $size . '&d=mm';
|
||||
}
|
||||
|
||||
private function getGravatarAvatarUrl($size)
|
||||
{
|
||||
$subject = !empty($this->getConfirmedEmail())
|
||||
? $this->getConfirmedEmail()
|
||||
: $this->passSalt . $this->getName();
|
||||
$hash = md5(strtolower(trim($subject)));
|
||||
return 'http://www.gravatar.com/avatar/' . $hash . '?s=' . $size . '&d=retro';
|
||||
}
|
||||
|
||||
private function getCustomAvatarUrl($size)
|
||||
{
|
||||
$fileName = md5($this->getName()) . '-' . $size . '.avatar';
|
||||
$path = $this->getCustomAvatarPath($size);
|
||||
if (!file_exists($path))
|
||||
$this->generateCustomAvatar($size);
|
||||
if (file_exists($path))
|
||||
return \Chibi\Util\Url::makeAbsolute('/avatars/' . $fileName);
|
||||
return $this->getBlankAvatarUrl($size);
|
||||
}
|
||||
|
||||
private function getCustomAvatarSourcePath()
|
||||
{
|
||||
$fileName = md5($this->getName()) . '.avatar_source';
|
||||
return Core::getConfig()->main->avatarsPath . DS . $fileName;
|
||||
}
|
||||
|
||||
private function getCustomAvatarPath($size)
|
||||
{
|
||||
$fileName = md5($this->getName()) . '-' . $size . '.avatar';
|
||||
return Core::getConfig()->main->avatarsPath . DS . $fileName;
|
||||
}
|
||||
|
||||
private function getCustomAvatarPaths()
|
||||
{
|
||||
$hash = md5($this->getName());
|
||||
return glob(Core::getConfig()->main->avatarsPath . DS . $hash . '*.avatar');
|
||||
}
|
||||
|
||||
private function removeOldCustomAvatar()
|
||||
{
|
||||
foreach ($this->getCustomAvatarPaths() as $path)
|
||||
TransferHelper::remove($path);
|
||||
}
|
||||
|
||||
private function generateCustomAvatar($size)
|
||||
{
|
||||
$srcPath = $this->getCustomAvatarSourcePath($size);
|
||||
$dstPath = $this->getCustomAvatarPath($size);
|
||||
|
||||
$thumbnailGenerator = new ImageThumbnailGenerator();
|
||||
return $thumbnailGenerator->generateFromFile(
|
||||
$srcPath,
|
||||
$dstPath,
|
||||
$size,
|
||||
$size);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ final class UserModel extends AbstractCrudModel
|
|||
'access_rank' => $user->getAccessRank()->toInteger(),
|
||||
'settings' => $user->getSettings()->getAllAsSerializedString(),
|
||||
'banned' => $user->isBanned() ? 1 : 0,
|
||||
'avatar_style' => $user->getAvatarStyle()->toInteger(),
|
||||
];
|
||||
|
||||
$stmt = (new Sql\UpdateStatement)
|
||||
|
|
1
src/Upgrades/mysql/Upgrade15.sql
Normal file
1
src/Upgrades/mysql/Upgrade15.sql
Normal file
|
@ -0,0 +1 @@
|
|||
ALTER TABLE user ADD COLUMN avatar_style INTEGER DEFAULT 1;
|
1
src/Upgrades/sqlite/Upgrade15.sql
Normal file
1
src/Upgrades/sqlite/Upgrade15.sql
Normal file
|
@ -0,0 +1 @@
|
|||
ALTER TABLE user ADD COLUMN avatar_style INTEGER DEFAULT 1;
|
|
@ -19,7 +19,7 @@ $noAutocomplete = isset($this->context->noAutocomplete) ? true : false;
|
|||
<?php if ($noAutocomplete): ?>
|
||||
autocomplete="off"
|
||||
<?php endif ?>
|
||||
<?php if ($inputClass != ''): ?>
|
||||
<?php if ($inputClass): ?>
|
||||
class="<?= $inputClass ?>"
|
||||
<?php endif ?>
|
||||
type="<?= $type ?>"
|
||||
|
|
|
@ -7,6 +7,7 @@ $optionLabels = $this->context->optionLabels;
|
|||
$optionNames = $this->context->optionNames;
|
||||
$optionStates = $this->context->optionStates;
|
||||
$keys = array_keys($optionNames);
|
||||
$inputClass = isset($this->context->inputClass) ? $this->context->inputClass : '';
|
||||
?>
|
||||
|
||||
<div class="form-row">
|
||||
|
@ -17,6 +18,9 @@ $keys = array_keys($optionNames);
|
|||
|
||||
<?php foreach ($keys as $key): ?>
|
||||
<input type="hidden"
|
||||
<?php if ($inputClass): ?>
|
||||
class="<?= $inputclass ?>"
|
||||
<?php endif ?>
|
||||
name="<?= $optionNames[$key] ?>"
|
||||
value="<?= $optionValuesDisabled[$key] ?>"/>
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ $optionValues = $this->context->optionValues;
|
|||
$optionLabels = $this->context->optionLabels;
|
||||
$activeOptionValue = $this->context->activeOptionValue;
|
||||
$keys = array_keys($optionValues);
|
||||
$inputClass = isset($this->context->inputClass) ? $this->context->inputClass : '';
|
||||
?>
|
||||
|
||||
<div class="form-row">
|
||||
|
@ -18,6 +19,9 @@ $keys = array_keys($optionValues);
|
|||
<label>
|
||||
<input type="radio"
|
||||
name="<?= $name ?>"
|
||||
<?php if ($inputClass): ?>
|
||||
class="<?= $inputClass ?>"
|
||||
<?php endif ?>
|
||||
<?php if (count($keys) == 1): ?>
|
||||
id="<?= $id ?>"
|
||||
<?php endif ?>
|
||||
|
|
|
@ -6,6 +6,7 @@ $optionValues = $this->context->optionValues;
|
|||
$optionLabels = $this->context->optionLabels;
|
||||
$activeOptionValue = isset($this->context->activeOptionValue) ? $this->context->activeOptionValue : null;
|
||||
$keys = array_keys($optionValues);
|
||||
$inputClass = isset($this->context->inputClass) ? $this->context->inputClass : '';
|
||||
?>
|
||||
|
||||
<div class="form-row">
|
||||
|
@ -13,7 +14,13 @@ $keys = array_keys($optionValues);
|
|||
<?= $label ?>
|
||||
</label>
|
||||
<div class="input-wrapper">
|
||||
<select name="<?= $name ?>" id="<?= $id ?>">
|
||||
<select
|
||||
<?php if ($inputClass): ?>
|
||||
class="<?= $inputclass ?>"
|
||||
<?php endif ?>
|
||||
name="<?= $name ?>"
|
||||
id="<?= $id ?>">
|
||||
|
||||
<?php foreach ($keys as $key): ?>
|
||||
<?php if ($activeOptionValue == $optionValues[$key]): ?>
|
||||
<option value="<?= $optionValues[$key] ?>" selected="selected">
|
||||
|
@ -23,6 +30,7 @@ $keys = array_keys($optionValues);
|
|||
<?= $optionLabels[$key] ?>
|
||||
</option>
|
||||
<?php endforeach ?>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
<?php
|
||||
$this->assets->addScript('user-edit.js');
|
||||
?>
|
||||
|
||||
<form
|
||||
action="<?= \Chibi\Router::linkTo(
|
||||
['UserController', 'editAction'],
|
||||
['identifier' => $this->context->transport->user->getName()]) ?>"
|
||||
enctype="multipart/form-data"
|
||||
method="post"
|
||||
class="edit"
|
||||
autocomplete="off">
|
||||
|
@ -17,6 +22,26 @@
|
|||
echo '<hr/>';
|
||||
}
|
||||
|
||||
if (Access::check(new Privilege(
|
||||
Privilege::EditUserAvatar,
|
||||
Access::getIdentity($this->context->transport->user))))
|
||||
{
|
||||
$styles = UserAvatarStyle::getAll();
|
||||
$context = new StdClass;
|
||||
$context->name = 'avatar-style';
|
||||
$context->label = 'User picture';
|
||||
$context->optionValues = array_map(function($s) { return $s->toInteger(); }, $styles);
|
||||
$context->optionLabels = array_map(function($s) { return ucfirst($s->toDisplayString()); }, $styles);
|
||||
$context->activeOptionValue = $this->context->transport->user->getAvatarStyle()->toInteger();
|
||||
$context->inputClass = 'avatar-style';
|
||||
$this->renderExternal('input-radioboxes', $context);
|
||||
|
||||
$context = new StdClass;
|
||||
$context->name = 'avatar-content';
|
||||
$context->inputClass = 'avatar-content';
|
||||
$this->renderExternal('input-file', $context);
|
||||
}
|
||||
|
||||
if (Access::check(new Privilege(
|
||||
Privilege::EditUserName,
|
||||
Access::getIdentity($this->context->transport->user))))
|
||||
|
|
|
@ -68,6 +68,7 @@ final class Core
|
|||
|
||||
TransferHelper::createDirectory($config->main->filesPath);
|
||||
TransferHelper::createDirectory($config->main->thumbnailsPath);
|
||||
TransferHelper::createDirectory($config->main->avatarsPath);
|
||||
|
||||
//extension sanity checks
|
||||
$requiredExtensions = ['pdo', 'pdo_' . $config->main->dbDriver, 'openssl', 'fileinfo'];
|
||||
|
|
|
@ -113,6 +113,7 @@ class SzurubooruTestRunner implements ITestRunner
|
|||
[
|
||||
realpath(Core::getConfig()->main->filesPath),
|
||||
realpath(Core::getConfig()->main->thumbnailsPath),
|
||||
realpath(Core::getConfig()->main->avatarsPath),
|
||||
realpath(dirname(Core::getConfig()->main->logsPath)),
|
||||
];
|
||||
|
||||
|
|
|
@ -147,6 +147,15 @@ class ApiArgumentTest extends AbstractFullApiTest
|
|||
JobArgs::ARG_NEW_USER_NAME));
|
||||
}
|
||||
|
||||
public function testEditUserAvatarJob()
|
||||
{
|
||||
$this->testArguments(new EditUserAvatarJob(),
|
||||
JobArgs::Conjunction(
|
||||
$this->getUserSelector(),
|
||||
JobArgs::ARG_NEW_AVATAR_STYLE,
|
||||
JobArgs::Optional(JobArgs::ARG_NEW_AVATAR_CONTENT)));
|
||||
}
|
||||
|
||||
public function testEditUserPasswordJob()
|
||||
{
|
||||
$this->testArguments(new EditUserPasswordJob(),
|
||||
|
|
|
@ -24,6 +24,7 @@ class ApiAuthTest extends AbstractFullApiTest
|
|||
$this->testAuth(new EditUserEmailJob(), false);
|
||||
$this->testAuth(new EditUserNameJob(), false);
|
||||
$this->testAuth(new EditUserPasswordJob(), false);
|
||||
$this->testAuth(new EditUserAvatarJob(), false);
|
||||
$this->testAuth(new EditUserSettingsJob(), false);
|
||||
$this->testAuth(new FeaturePostJob(), true);
|
||||
$this->testAuth(new FlagPostJob(), false);
|
||||
|
|
|
@ -25,6 +25,7 @@ class ApiEmailRequirementsTest extends AbstractFullApiTest
|
|||
$this->testRegularEmailRequirement(new EditUserEmailJob());
|
||||
$this->testRegularEmailRequirement(new EditUserNameJob());
|
||||
$this->testRegularEmailRequirement(new EditUserPasswordJob());
|
||||
$this->testRegularEmailRequirement(new EditUserAvatarJob());
|
||||
$this->testRegularEmailRequirement(new EditUserSettingsJob());
|
||||
$this->testRegularEmailRequirement(new FeaturePostJob());
|
||||
$this->testRegularEmailRequirement(new FlagPostJob());
|
||||
|
|
|
@ -134,6 +134,7 @@ class ApiPrivilegeTest extends AbstractFullApiTest
|
|||
$this->testDynamicUserPrivilege(new EditUserEmailJob(), Privilege::EditUserEmail);
|
||||
$this->testDynamicUserPrivilege(new EditUserNameJob(), Privilege::EditUserName);
|
||||
$this->testDynamicUserPrivilege(new EditUserPasswordJob(), Privilege::EditUserPassword);
|
||||
$this->testDynamicUserPrivilege(new EditUserAvatarJob(), Privilege::EditUserAvatar);
|
||||
$this->testDynamicUserPrivilege(new EditUserSettingsJob(), Privilege::EditUserSettings);
|
||||
|
||||
$ctx = function($job)
|
||||
|
@ -145,6 +146,7 @@ class ApiPrivilegeTest extends AbstractFullApiTest
|
|||
$this->testDynamicUserPrivilege($ctx(new EditUserEmailJob()), Privilege::RegisterAccount);
|
||||
$this->testDynamicUserPrivilege($ctx(new EditUserNameJob()), Privilege::RegisterAccount);
|
||||
$this->testDynamicUserPrivilege($ctx(new EditUserPasswordJob()), Privilege::RegisterAccount);
|
||||
$this->testDynamicUserPrivilege($ctx(new EditUserAvatarJob()), Privilege::RegisterAccount);
|
||||
$this->testDynamicUserPrivilege($ctx(new EditUserSettingsJob()), Privilege::EditUserSettings);
|
||||
|
||||
$this->testDynamicUserPrivilege(new FlagUserJob(), Privilege::FlagUser);
|
||||
|
|
88
tests/Tests/JobTests/EditUserAvatarJobTest.php
Normal file
88
tests/Tests/JobTests/EditUserAvatarJobTest.php
Normal file
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
class EditUserAvatarJobTest extends AbstractTest
|
||||
{
|
||||
public function testGravatar()
|
||||
{
|
||||
$this->grantAccess('editUserAvatar');
|
||||
$user = $this->userMocker->mockSingle();
|
||||
|
||||
$this->assert->areEqual(UserAvatarStyle::Gravatar, $user->getAvatarStyle()->toInteger());
|
||||
|
||||
$user = $this->assert->doesNotThrow(function() use ($user)
|
||||
{
|
||||
return Api::run(
|
||||
new EditUserAvatarJob(),
|
||||
[
|
||||
JobArgs::ARG_USER_NAME => $user->getName(),
|
||||
JobArgs::ARG_NEW_AVATAR_STYLE => UserAvatarStyle::Gravatar,
|
||||
]);
|
||||
});
|
||||
|
||||
$this->assert->areEqual(UserAvatarStyle::Gravatar, $user->getAvatarStyle()->toInteger());
|
||||
|
||||
$hash = md5($user->getPasswordSalt() . $user->getName());
|
||||
$this->assert->isTrue(strpos($user->getAvatarUrl(), $hash) !== false);
|
||||
|
||||
$mail = 'postmaster@mordor.cx';
|
||||
$user->setConfirmedEmail($mail);
|
||||
UserModel::save($user);
|
||||
|
||||
$hash = md5($mail);
|
||||
$this->assert->isTrue(strpos($user->getAvatarUrl(), $hash) !== false);
|
||||
}
|
||||
|
||||
public function testEmpty()
|
||||
{
|
||||
$this->grantAccess('editUserAvatar');
|
||||
$user = $this->userMocker->mockSingle();
|
||||
|
||||
$this->assert->areEqual(UserAvatarStyle::Gravatar, $user->getAvatarStyle()->toInteger());
|
||||
|
||||
$user = $this->assert->doesNotThrow(function() use ($user)
|
||||
{
|
||||
return Api::run(
|
||||
new EditUserAvatarJob(),
|
||||
[
|
||||
JobArgs::ARG_USER_NAME => $user->getName(),
|
||||
JobArgs::ARG_NEW_AVATAR_STYLE => UserAvatarStyle::None,
|
||||
]);
|
||||
});
|
||||
|
||||
$this->assert->areEqual(UserAvatarStyle::None, $user->getAvatarStyle()->toInteger());
|
||||
|
||||
$hash = md5($user->getPasswordSalt() . $user->getName());
|
||||
$this->assert->isTrue(strpos($user->getAvatarUrl(), $hash) === false);
|
||||
|
||||
$mail = 'postmaster@mordor.cx';
|
||||
$user->setConfirmedEmail($mail);
|
||||
UserModel::save($user);
|
||||
|
||||
$hash = md5($mail);
|
||||
$this->assert->isTrue(strpos($user->getAvatarUrl(), $hash) === false);
|
||||
}
|
||||
|
||||
public function testCustom()
|
||||
{
|
||||
$this->grantAccess('editUserAvatar');
|
||||
$user = $this->userMocker->mockSingle();
|
||||
|
||||
$this->assert->areEqual(UserAvatarStyle::Gravatar, $user->getAvatarStyle()->toInteger());
|
||||
|
||||
$user = $this->assert->doesNotThrow(function() use ($user)
|
||||
{
|
||||
return Api::run(
|
||||
new EditUserAvatarJob(),
|
||||
[
|
||||
JobArgs::ARG_USER_NAME => $user->getName(),
|
||||
JobArgs::ARG_NEW_AVATAR_STYLE => UserAvatarStyle::Custom,
|
||||
JobArgs::ARG_NEW_AVATAR_CONTENT => new ApiFileInput($this->testSupport->getPath('image.jpg'), 'image.jpg')
|
||||
]);
|
||||
});
|
||||
|
||||
$this->assert->areEqual(UserAvatarStyle::Custom, $user->getAvatarStyle()->toInteger());
|
||||
|
||||
$hash = md5($user->getPasswordSalt() . $user->getName());
|
||||
$this->assert->isTrue(strpos($user->getAvatarUrl(), $hash) === false);
|
||||
$this->assert->isTrue(strpos($user->getAvatarUrl(32), '32') !== false);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
[main]
|
||||
filesPath = "./tests/files/"
|
||||
thumbnailsPath = "./tests/thumbs/"
|
||||
avatarsPath = "./tests/avatars/"
|
||||
logsPath = "./tests/logs/{yyyy}-{mm}.log"
|
||||
mediaPath = "./public_html/media/"
|
||||
title = "szurubooru/tests"
|
||||
|
|
Loading…
Reference in a new issue