2013-12-18 15:10:53 +01:00
|
|
|
<?php
|
2014-02-28 20:35:12 +01:00
|
|
|
use \Chibi\Sql as Sql;
|
|
|
|
use \Chibi\Database as Database;
|
|
|
|
|
2014-05-05 09:36:08 +02:00
|
|
|
class UserEntity extends AbstractEntity implements IValidatable
|
2013-12-18 15:10:53 +01:00
|
|
|
{
|
2014-05-04 20:09:03 +02:00
|
|
|
protected $name;
|
2014-05-07 00:34:02 +02:00
|
|
|
protected $passSalt;
|
|
|
|
protected $passHash;
|
2013-12-18 15:10:53 +01:00
|
|
|
public $staffConfirmed;
|
2014-05-07 09:26:04 +02:00
|
|
|
protected $emailUnconfirmed;
|
|
|
|
protected $emailConfirmed;
|
2014-05-07 20:33:52 +02:00
|
|
|
protected $joinDate;
|
|
|
|
protected $lastLoginDate;
|
2014-05-04 19:06:40 +02:00
|
|
|
protected $accessRank;
|
2013-12-18 15:10:53 +01:00
|
|
|
public $settings;
|
2014-05-04 20:09:03 +02:00
|
|
|
protected $banned = false;
|
|
|
|
|
2014-05-07 00:34:02 +02:00
|
|
|
protected $__passwordChanged = false;
|
|
|
|
protected $__password;
|
|
|
|
|
2014-05-05 09:36:08 +02:00
|
|
|
public function validate()
|
|
|
|
{
|
2014-05-07 00:34:02 +02:00
|
|
|
$this->validateUserName();
|
|
|
|
$this->validatePassword();
|
|
|
|
|
|
|
|
//todo: validate e-mails
|
|
|
|
|
2014-05-05 09:36:08 +02:00
|
|
|
if (empty($this->getAccessRank()))
|
2014-05-07 00:34:02 +02:00
|
|
|
throw new Exception('No access rank detected');
|
2014-05-05 09:36:08 +02:00
|
|
|
|
|
|
|
if ($this->getAccessRank()->toInteger() == AccessRank::Anonymous)
|
|
|
|
throw new Exception('Trying to save anonymous user into database');
|
|
|
|
}
|
|
|
|
|
2014-05-07 00:34:02 +02:00
|
|
|
protected function validateUserName()
|
|
|
|
{
|
|
|
|
$userName = $this->getName();
|
|
|
|
$config = getConfig();
|
|
|
|
|
|
|
|
$otherUser = UserModel::findByName($userName, false);
|
|
|
|
if ($otherUser !== null and $otherUser->getId() != $this->getId())
|
|
|
|
{
|
2014-05-07 09:26:04 +02:00
|
|
|
if (!$otherUser->getConfirmedEmail()
|
2014-05-07 00:34:02 +02:00
|
|
|
and isset($config->registration->needEmailForRegistering)
|
|
|
|
and $config->registration->needEmailForRegistering)
|
|
|
|
{
|
|
|
|
throw new SimpleException('User with this name is already registered and awaits e-mail confirmation');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$otherUser->staffConfirmed
|
|
|
|
and $config->registration->staffActivation)
|
|
|
|
{
|
|
|
|
throw new SimpleException('User with this name is already registered and awaits staff confirmation');
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new SimpleException('User with this name is already registered');
|
|
|
|
}
|
|
|
|
|
|
|
|
$userNameMinLength = intval($config->registration->userNameMinLength);
|
|
|
|
$userNameMaxLength = intval($config->registration->userNameMaxLength);
|
|
|
|
$userNameRegex = $config->registration->userNameRegex;
|
|
|
|
|
|
|
|
if (strlen($userName) < $userNameMinLength)
|
|
|
|
throw new SimpleException('User name must have at least %d characters', $userNameMinLength);
|
|
|
|
|
|
|
|
if (strlen($userName) > $userNameMaxLength)
|
|
|
|
throw new SimpleException('User name must have at most %d characters', $userNameMaxLength);
|
|
|
|
|
|
|
|
if (!preg_match($userNameRegex, $userName))
|
|
|
|
throw new SimpleException('User name contains invalid characters');
|
|
|
|
}
|
|
|
|
|
|
|
|
public function validatePassword()
|
|
|
|
{
|
|
|
|
if (empty($this->getPasswordHash()))
|
|
|
|
throw new Exception('Trying to save user with no password into database');
|
|
|
|
|
|
|
|
if (!$this->__passwordChanged)
|
|
|
|
return;
|
|
|
|
|
|
|
|
$config = getConfig();
|
|
|
|
$passMinLength = intval($config->registration->passMinLength);
|
|
|
|
$passRegex = $config->registration->passRegex;
|
|
|
|
|
|
|
|
$password = $this->__password;
|
|
|
|
|
|
|
|
if (strlen($password) < $passMinLength)
|
|
|
|
throw new SimpleException('Password must have at least %d characters', $passMinLength);
|
|
|
|
|
|
|
|
if (!preg_match($passRegex, $password))
|
|
|
|
throw new SimpleException('Password contains invalid characters');
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function validateAccessRank(AccessRank $accessRank)
|
|
|
|
{
|
|
|
|
$accessRank->validate();
|
|
|
|
|
|
|
|
if ($accessRank->toInteger() == AccessRank::Nobody)
|
|
|
|
throw new Exception('Cannot set special access rank "%s"', $accessRank->toString());
|
|
|
|
|
|
|
|
return $accessRank;
|
|
|
|
}
|
|
|
|
|
2014-05-07 20:33:52 +02:00
|
|
|
|
2014-05-04 20:09:03 +02:00
|
|
|
public function isBanned()
|
|
|
|
{
|
|
|
|
return $this->banned;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function ban()
|
|
|
|
{
|
|
|
|
$this->banned = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function unban()
|
|
|
|
{
|
|
|
|
$this->banned = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getName()
|
|
|
|
{
|
|
|
|
return $this->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setName($name)
|
|
|
|
{
|
2014-05-07 00:34:02 +02:00
|
|
|
$this->name = trim($name);
|
|
|
|
}
|
|
|
|
|
2014-05-07 20:33:52 +02:00
|
|
|
public function getJoinTime()
|
|
|
|
{
|
|
|
|
return $this->joinDate;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setJoinTime($unixTime)
|
|
|
|
{
|
|
|
|
$this->joinDate = $unixTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getLastLoginTime()
|
|
|
|
{
|
|
|
|
return $this->lastLoginDate;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setLastLoginTime($unixTime)
|
|
|
|
{
|
|
|
|
$this->lastLoginDate = $unixTime;
|
|
|
|
}
|
|
|
|
|
2014-05-07 09:26:04 +02:00
|
|
|
public function getUnconfirmedEmail()
|
|
|
|
{
|
|
|
|
return $this->emailUnconfirmed;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setUnconfirmedEmail($email)
|
|
|
|
{
|
|
|
|
$this->emailUnconfirmed = $email;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getConfirmedEmail()
|
|
|
|
{
|
|
|
|
return $this->emailConfirmed;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setConfirmedEmail($email)
|
|
|
|
{
|
|
|
|
$this->emailConfirmed = $email;
|
|
|
|
}
|
|
|
|
|
2014-05-07 00:34:02 +02:00
|
|
|
public function getPasswordHash()
|
|
|
|
{
|
|
|
|
return $this->passHash;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getPasswordSalt()
|
|
|
|
{
|
|
|
|
return $this->passSalt;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setPasswordSalt($passSalt)
|
|
|
|
{
|
|
|
|
$this->passSalt = $passSalt;
|
|
|
|
$this->passHash = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setPassword($password)
|
|
|
|
{
|
|
|
|
$this->__passwordChanged = true;
|
|
|
|
$this->__password = $password;
|
|
|
|
$this->passHash = UserModel::hashPassword($password, $this->passSalt);
|
2014-05-04 20:09:03 +02:00
|
|
|
}
|
2013-12-18 15:10:53 +01:00
|
|
|
|
2014-05-04 19:06:40 +02:00
|
|
|
public function getAccessRank()
|
|
|
|
{
|
|
|
|
return $this->accessRank;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setAccessRank(AccessRank $accessRank)
|
|
|
|
{
|
|
|
|
$accessRank->validate();
|
|
|
|
$this->accessRank = $accessRank;
|
|
|
|
}
|
|
|
|
|
2013-12-18 15:10:53 +01:00
|
|
|
public function getAvatarUrl($size = 32)
|
|
|
|
{
|
2014-05-07 09:26:04 +02:00
|
|
|
$subject = !empty($this->getConfirmedEmail())
|
|
|
|
? $this->getConfirmedEmail()
|
2014-05-04 20:09:03 +02:00
|
|
|
: $this->passSalt . $this->getName();
|
2013-12-18 15:10:53 +01:00
|
|
|
$hash = md5(strtolower(trim($subject)));
|
|
|
|
$url = 'http://www.gravatar.com/avatar/' . $hash . '?s=' . $size . '&d=retro';
|
|
|
|
return $url;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getSetting($key)
|
|
|
|
{
|
|
|
|
$settings = json_decode($this->settings, true);
|
|
|
|
return isset($settings[$key])
|
|
|
|
? $settings[$key]
|
|
|
|
: null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setSetting($key, $value)
|
|
|
|
{
|
|
|
|
$settings = json_decode($this->settings, true);
|
|
|
|
$settings[$key] = $value;
|
|
|
|
$settings = json_encode($settings);
|
|
|
|
if (strlen($settings) > 200)
|
|
|
|
throw new SimpleException('Too much data');
|
|
|
|
$this->settings = $settings;
|
|
|
|
}
|
|
|
|
|
2014-05-04 19:06:40 +02:00
|
|
|
public function hasEnabledSafety(PostSafety $safety)
|
2013-12-18 15:10:53 +01:00
|
|
|
{
|
|
|
|
$all = $this->getSetting(UserModel::SETTING_SAFETY);
|
|
|
|
if (!$all)
|
2014-05-04 19:06:40 +02:00
|
|
|
return $safety->toInteger() == PostSafety::Safe;
|
|
|
|
return $all & $safety->toFlag();
|
2013-12-18 15:10:53 +01:00
|
|
|
}
|
|
|
|
|
2014-05-04 19:06:40 +02:00
|
|
|
public function enableSafety(PostSafety $safety, $enabled)
|
2013-12-18 15:10:53 +01:00
|
|
|
{
|
|
|
|
$all = $this->getSetting(UserModel::SETTING_SAFETY);
|
|
|
|
|
|
|
|
$new = $all;
|
|
|
|
if (!$enabled)
|
|
|
|
{
|
2014-05-04 19:06:40 +02:00
|
|
|
$new &= ~$safety->toFlag();
|
2013-12-18 15:10:53 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-05-04 19:06:40 +02:00
|
|
|
$new |= $safety->toFlag();
|
2013-12-18 15:10:53 +01:00
|
|
|
}
|
|
|
|
|
2014-05-04 19:06:40 +02:00
|
|
|
if (!$new)
|
|
|
|
$new = (new PostSafety(PostSafety::Safe))->toFlag();
|
|
|
|
|
2013-12-18 15:10:53 +01:00
|
|
|
$this->setSetting(UserModel::SETTING_SAFETY, $new);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function hasEnabledHidingDislikedPosts()
|
|
|
|
{
|
|
|
|
$ret = $this->getSetting(UserModel::SETTING_HIDE_DISLIKED_POSTS);
|
|
|
|
if ($ret === null)
|
2014-04-29 21:35:29 +02:00
|
|
|
$ret = !getConfig()->browsing->showDislikedPostsDefault;
|
2013-12-18 15:10:53 +01:00
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function enableHidingDislikedPosts($enabled)
|
|
|
|
{
|
|
|
|
$this->setSetting(UserModel::SETTING_HIDE_DISLIKED_POSTS, $enabled ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function hasEnabledPostTagTitles()
|
|
|
|
{
|
|
|
|
$ret = $this->getSetting(UserModel::SETTING_POST_TAG_TITLES);
|
|
|
|
if ($ret === null)
|
2014-04-29 21:35:29 +02:00
|
|
|
$ret = getConfig()->browsing->showPostTagTitlesDefault;
|
2013-12-18 15:10:53 +01:00
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function enablePostTagTitles($enabled)
|
|
|
|
{
|
|
|
|
$this->setSetting(UserModel::SETTING_POST_TAG_TITLES, $enabled ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function hasEnabledEndlessScrolling()
|
|
|
|
{
|
|
|
|
$ret = $this->getSetting(UserModel::SETTING_ENDLESS_SCROLLING);
|
|
|
|
if ($ret === null)
|
2014-04-29 21:35:29 +02:00
|
|
|
$ret = getConfig()->browsing->endlessScrollingDefault;
|
2013-12-18 15:10:53 +01:00
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function enableEndlessScrolling($enabled)
|
|
|
|
{
|
|
|
|
$this->setSetting(UserModel::SETTING_ENDLESS_SCROLLING, $enabled ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
2014-05-04 15:43:38 +02:00
|
|
|
public function confirmEmail()
|
|
|
|
{
|
2014-05-07 09:26:04 +02:00
|
|
|
if (empty($this->getUnconfirmedEmail()))
|
2014-05-04 15:43:38 +02:00
|
|
|
return;
|
|
|
|
|
2014-05-07 09:26:04 +02:00
|
|
|
$this->setConfirmedEmail($this->getUnconfirmedEmail());
|
|
|
|
$this->setUnconfirmedEmail(null);
|
2014-05-04 15:43:38 +02:00
|
|
|
}
|
|
|
|
|
2013-12-18 15:10:53 +01:00
|
|
|
public function hasFavorited($post)
|
|
|
|
{
|
2014-02-28 20:35:12 +01:00
|
|
|
$stmt = new Sql\SelectStatement();
|
|
|
|
$stmt->setColumn(new Sql\AliasFunctor(new Sql\CountFunctor('1'), 'count'));
|
2014-02-22 19:21:32 +01:00
|
|
|
$stmt->setTable('favoritee');
|
2014-02-28 20:35:12 +01:00
|
|
|
$stmt->setCriterion((new Sql\ConjunctionFunctor)
|
2014-05-05 21:20:40 +02:00
|
|
|
->add(new Sql\EqualsFunctor('user_id', new Sql\Binding($this->getId())))
|
|
|
|
->add(new Sql\EqualsFunctor('post_id', new Sql\Binding($post->getId()))));
|
2014-02-22 19:21:32 +01:00
|
|
|
return Database::fetchOne($stmt)['count'] == 1;
|
2013-12-18 15:10:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getScore($post)
|
|
|
|
{
|
2014-02-28 20:35:12 +01:00
|
|
|
$stmt = new Sql\SelectStatement();
|
2014-02-22 19:21:32 +01:00
|
|
|
$stmt->setColumn('score');
|
|
|
|
$stmt->setTable('post_score');
|
2014-02-28 20:35:12 +01:00
|
|
|
$stmt->setCriterion((new Sql\ConjunctionFunctor)
|
2014-05-05 21:20:40 +02:00
|
|
|
->add(new Sql\EqualsFunctor('user_id', new Sql\Binding($this->getId())))
|
|
|
|
->add(new Sql\EqualsFunctor('post_id', new Sql\Binding($post->getId()))));
|
2014-02-22 19:21:32 +01:00
|
|
|
$row = Database::fetchOne($stmt);
|
2013-12-18 15:10:53 +01:00
|
|
|
if ($row)
|
|
|
|
return intval($row['score']);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getFavoriteCount()
|
|
|
|
{
|
2014-02-28 20:35:12 +01:00
|
|
|
$stmt = new Sql\SelectStatement();
|
|
|
|
$stmt->setColumn(new Sql\AliasFunctor(new Sql\CountFunctor('1'), 'count'));
|
2014-02-22 19:21:32 +01:00
|
|
|
$stmt->setTable('favoritee');
|
2014-05-05 21:20:40 +02:00
|
|
|
$stmt->setCriterion(new Sql\EqualsFunctor('user_id', new Sql\Binding($this->getId())));
|
2014-02-22 19:21:32 +01:00
|
|
|
return Database::fetchOne($stmt)['count'];
|
2013-12-18 15:10:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getCommentCount()
|
|
|
|
{
|
2014-02-28 20:35:12 +01:00
|
|
|
$stmt = new Sql\SelectStatement();
|
|
|
|
$stmt->setColumn(new Sql\AliasFunctor(new Sql\CountFunctor('1'), 'count'));
|
2014-02-22 19:21:32 +01:00
|
|
|
$stmt->setTable('comment');
|
2014-05-05 21:20:40 +02:00
|
|
|
$stmt->setCriterion(new Sql\EqualsFunctor('commenter_id', new Sql\Binding($this->getId())));
|
2014-02-22 19:21:32 +01:00
|
|
|
return Database::fetchOne($stmt)['count'];
|
2013-12-18 15:10:53 +01:00
|
|
|
}
|
2013-12-23 16:43:06 +01:00
|
|
|
|
|
|
|
public function getPostCount()
|
|
|
|
{
|
2014-02-28 20:35:12 +01:00
|
|
|
$stmt = new Sql\SelectStatement();
|
|
|
|
$stmt->setColumn(new Sql\AliasFunctor(new Sql\CountFunctor('1'), 'count'));
|
2014-02-22 19:21:32 +01:00
|
|
|
$stmt->setTable('post');
|
2014-05-05 21:20:40 +02:00
|
|
|
$stmt->setCriterion(new Sql\EqualsFunctor('uploader_id', new Sql\Binding($this->getId())));
|
2014-02-22 19:21:32 +01:00
|
|
|
return Database::fetchOne($stmt)['count'];
|
2013-12-23 16:43:06 +01:00
|
|
|
}
|
2013-12-18 15:10:53 +01:00
|
|
|
}
|