src/models/Message.php
<?php
namespace bizley\podium\models;
use bizley\podium\db\Query;
use bizley\podium\log\Log;
use bizley\podium\models\db\MessageActiveRecord;
use bizley\podium\models\User;
use bizley\podium\Podium;
use cebe\markdown\GithubMarkdown;
use Exception;
use Yii;
use yii\helpers\Html;
use yii\helpers\Url;
/**
* Message model
*
* @author Paweł Bizley Brzozowski <pawel@positive.codes>
* @since 0.1
*
* @property string $parsedContent
*/
class Message extends MessageActiveRecord
{
/**
* Limits.
*/
const MAX_RECEIVERS = 10;
const SPAM_MESSAGES = 10;
const SPAM_WAIT = 1;
/**
* Returns Re: prefix for subject.
* @return string
*/
public static function re()
{
return Yii::t('podium/view', 'Re:');
}
/**
* Checks if user is a message receiver.
* @param int $userId
* @return bool
*/
public function isMessageReceiver($userId)
{
if ($this->messageReceivers) {
foreach ($this->messageReceivers as $receiver) {
if ($receiver->receiver_id == $userId) {
return true;
}
}
}
return false;
}
/**
* Sends message.
* @return bool
*/
public function send()
{
$transaction = static::getDb()->beginTransaction();
try {
$this->sender_id = User::loggedId();
$this->sender_status = self::STATUS_READ;
if (!$this->save()) {
throw new Exception('Message saving error!');
}
$count = count($this->receiversId);
foreach ($this->receiversId as $receiver) {
if (!(new Query())->select('id')->from(User::tableName())->where(['id' => $receiver, 'status' => User::STATUS_ACTIVE])->exists()) {
if ($count == 1) {
throw new Exception('No active receivers to send message to!');
}
continue;
}
$message = new MessageReceiver();
$message->message_id = $this->id;
$message->receiver_id = $receiver;
$message->receiver_status = self::STATUS_NEW;
if (!$message->save()) {
throw new Exception('MessageReceiver saving error!');
}
Podium::getInstance()->podiumCache->deleteElement('user.newmessages', $receiver);
}
$transaction->commit();
$sessionKey = 'messages.' . $this->sender_id;
if (Yii::$app->session->has($sessionKey)) {
$sentAlready = explode('|', Yii::$app->session->get($sessionKey));
$sentAlready[] = time();
Yii::$app->session->set($sessionKey, implode('|', $sentAlready));
} else {
Yii::$app->session->set($sessionKey, time());
}
return true;
} catch (Exception $e) {
$transaction->rollBack();
Log::error($e->getMessage(), $this->id, __METHOD__);
}
return false;
}
/**
* Checks if user sent already more than SPAM_MESSAGES in last SPAM_WAIT
* minutes.
* @param int $userId
* @return bool
*/
public static function tooMany($userId)
{
$sessionKey = 'messages.' . $userId;
if (Yii::$app->session->has($sessionKey)) {
$sentAlready = explode('|', Yii::$app->session->get($sessionKey));
$validated = [];
foreach ($sentAlready as $t) {
if (preg_match('/^[0-9]+$/', $t)) {
if ($t > time() - self::SPAM_WAIT * 60) {
$validated[] = $t;
}
}
}
Yii::$app->session->set($sessionKey, implode('|', $validated));
if (count($validated) >= self::SPAM_MESSAGES) {
return true;
}
}
return false;
}
/**
* Removes message.
* @return bool
*/
public function remove()
{
$transaction = static::getDb()->beginTransaction();
try {
$clearCache = false;
if ($this->sender_status == self::STATUS_NEW) {
$clearCache = true;
}
$this->scenario = 'remove';
if (empty($this->messageReceivers)) {
if (!$this->delete()) {
throw new Exception('Message removing error!');
}
if ($clearCache) {
Podium::getInstance()->podiumCache->deleteElement('user.newmessages', $this->sender_id);
}
$transaction->commit();
return true;
}
$allDeleted = true;
foreach ($this->messageReceivers as $mr) {
if ($mr->receiver_status != MessageReceiver::STATUS_DELETED) {
$allDeleted = false;
break;
}
}
if ($allDeleted) {
foreach ($this->messageReceivers as $mr) {
if (!$mr->delete()) {
throw new Exception('Received message removing error!');
}
}
if (!$this->delete()) {
throw new Exception('Message removing error!');
}
if ($clearCache) {
Podium::getInstance()->podiumCache->deleteElement('user.newmessages', $this->sender_id);
}
$transaction->commit();
return true;
}
$this->sender_status = self::STATUS_DELETED;
if (!$this->save()) {
throw new Exception('Message status changing error!');
}
if ($clearCache) {
Podium::getInstance()->podiumCache->deleteElement('user.newmessages', $this->sender_id);
}
$transaction->commit();
return true;
} catch (Exception $e) {
$transaction->rollBack();
Log::error($e->getMessage(), $this->id, __METHOD__);
}
return false;
}
/**
* Performs post report sending to moderators.
* @param Post $post reported post
* @return bool
* @since 0.2
*/
public function podiumReport($post = null)
{
try {
if (empty($post)) {
throw new Exception('Reported post missing');
}
$logged = User::loggedId();
$this->sender_id = $logged;
$this->topic = Yii::t('podium/view', 'Complaint about the post #{id}', ['id' => $post->id]);
if (Podium::getInstance()->podiumConfig->get('use_wysiwyg') == '0') {
$this->content .= "\n\n---\n"
. '[' . Yii::t('podium/view', 'Direct link to this post') . '](' . Url::to(['forum/show', 'id' => $post->id]) . ')'
. "\n\n---\n"
. '**' . Yii::t('podium/view', 'Post contents') . '**'
. $post->content;
} else {
$this->content .= '<hr>'
. Html::a(Yii::t('podium/view', 'Direct link to this post'), ['forum/show', 'id' => $post->id])
. '<hr>'
. '<p>' . Yii::t('podium/view', 'Post contents') . '</p>'
. '<blockquote>' . $post->content . '</blockquote>';
}
$this->sender_status = self::STATUS_DELETED;
if (!$this->save()) {
throw new Exception('Saving complaint error!');
}
$receivers = [];
$mods = $post->forum->mods;
$stamp = time();
foreach ($mods as $mod) {
if ($mod != $logged) {
$receivers[] = [$this->id, $mod, self::STATUS_NEW, $stamp, $stamp];
}
}
if (empty($receivers)) {
throw new Exception('No one to send report to');
}
if (!Podium::getInstance()->db->createCommand()->batchInsert(
MessageReceiver::tableName(),
['message_id', 'receiver_id', 'receiver_status', 'created_at', 'updated_at'],
$receivers
)->execute()) {
throw new Exception('Reports saving error!');
}
Podium::getInstance()->podiumCache->delete('user.newmessages');
Log::info('Post reported', $post->id, __METHOD__);
return true;
} catch (Exception $e) {
Log::error($e->getMessage(), null, __METHOD__);
}
return false;
}
/**
* Marks message read.
* @since 0.2
*/
public function markRead()
{
if ($this->sender_status == self::STATUS_NEW) {
$this->sender_status = self::STATUS_READ;
if ($this->save()) {
Podium::getInstance()->podiumCache->deleteElement('user.newmessages', $this->sender_id);
}
}
}
/**
* Returns content Markdown-parsed if WYSIWYG editor is switched off.
* @return string
* @since 0.6
*/
public function getParsedContent()
{
if (Podium::getInstance()->podiumConfig->get('use_wysiwyg') == '0') {
$parser = new GithubMarkdown();
$parser->html5 = true;
return $parser->parse($this->content);
}
return $this->content;
}
}