Add some pages for PM

This commit is contained in:
Visman 2021-03-30 22:11:36 +07:00
parent 3503b58702
commit 1da4df45ab
5 changed files with 646 additions and 0 deletions

75
app/Models/Pages/PM.php Normal file
View file

@ -0,0 +1,75 @@
<?php
/**
* This file is part of the ForkBB <https://github.com/forkbb>.
*
* @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
* @license The MIT License (MIT)
*/
declare(strict_types=1);
namespace ForkBB\Models\Pages;
use ForkBB\Models\Page;
use ForkBB\Models\PM\Cnst;
use function \ForkBB\__;
class PM extends Page
{
/**
* Точка входа для приватных сообщений
*/
public function action(array $args, string $method): Page
{
$second = null;
if (isset($args['second'])) {
if ('' === \trim($args['second'], '1234567890')) {
$second = (int) $args['second'];
} else {
$second = $args['second'];
}
}
$pms = $this->c->pms->init($second);
if (
null !== $second
&& empty($pms->idsCurrent)
&& empty($pms->idsArchive)
) {
return $this->c->Message->message('Not Found', true, 404);
}
$this->c->Lang->load('pm');
$action = $args['action'] ?? ($this->user->u_pm_num_new > 0 ? Cnst::ACTION_NEW : Cnst::ACTION_CURRENT);
switch ($action) {
case Cnst::ACTION_NEW:
case Cnst::ACTION_CURRENT:
case Cnst::ACTION_ARCHIVE:
$pms->area = $action;
return $this->c->PMView->view($args, $method);
case Cnst::ACTION_SEND:
$pms->area = Cnst::ACTION_CURRENT;
return $this->c->PMPost->post($args, $method);
case Cnst::ACTION_TOPIC:
return $this->c->PMTopic->topic($args, $method);
case Cnst::ACTION_POST:
return $this->c->PMTopic->post($args, $method);
case Cnst::ACTION_DELETE:
return $this->c->PMDelete->delete($args, $method);
case Cnst::ACTION_EDIT:
return $this->c->PMEdit->edit($args, $method);
case Cnst::ACTION_BLOCK:
return $this->c->PMBlock->block($args, $method);
case Cnst::ACTION_CONFIG:
return $this->c->PMConfig->config($args, $method);
default:
return $this->c->Message->message('Bad request');
}
}
}

View file

@ -0,0 +1,189 @@
<?php
/**
* This file is part of the ForkBB <https://github.com/forkbb>.
*
* @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
* @license The MIT License (MIT)
*/
declare(strict_types=1);
namespace ForkBB\Models\Pages\PM;
use ForkBB\Core\Container;
use ForkBB\Models\Page;
use ForkBB\Models\PM\Cnst;
use ForkBB\Models\User\Model as User;
use function \ForkBB\__;
abstract class AbstractPM extends Page
{
/**
* @var array
*/
protected $pmCrumbs = [];
/**
* @var ForkBB\Models\PM\Manager
*/
protected $pms;
public function __construct(Container $container)
{
parent::__construct($container);
$this->pms = $container->pms;
$this->pmIndex = Cnst::ACTION_CURRENT; # string Указатель на активный пункт навигации в меню ЛС
$this->fIndex = self::FI_PM;
$this->onlinePos = 'pm';
$this->robots = 'noindex, nofollow';
$this->hhsLevel = 'secure';
}
/**
* Подготовка страницы к отображению
*/
public function prepare(): void
{
$this->pmNavigation = $this->pmNavigation();
$this->crumbs = $this->crumbs(...$this->pmCrumbs);
parent::prepare();
}
/**
* Возвращает массив ссылок с описанием для построения навигации админки
*/
protected function pmNavigation(): array
{
$r = $this->c->Router;
$args = [
'second' => $this->pms->second,
];
$nav = [
'pm-boxes' => [true, 'PM Folders'],
Cnst::ACTION_NEW => [
$r->link('PMAction', $args + ['action' => Cnst::ACTION_NEW]),
$this->pms->numNew > 0 ? ['New messages %s', $this->pms->numNew] : 'New messages',
],
Cnst::ACTION_CURRENT => [
$r->link('PMAction', $args + ['action' => Cnst::ACTION_CURRENT]),
$this->pms->numCurrent > 0 ? ['My talks %s', $this->pms->numCurrent] : 'My talks',
],
Cnst::ACTION_ARCHIVE => [
$r->link('PMAction', $args + ['action' => Cnst::ACTION_ARCHIVE]),
$this->pms->numArchive > 0 ? ['Archive messages %s', $this->pms->numArchive] : 'Archive messages',
],
'pm-sp1' => [null, null],
];
$nav += [
'pm-storage' => [true, 'PM Storage'],
'pm-active' => [
false,
[
'Active: %s',
$this->user->g_pm_limit < 1 ? 0 : (int) (100 * $this->pms->totalCurrent / $this->user->g_pm_limit),
],
],
'pm-archive' => [
false,
[
'Archive: %s',
$this->user->g_pm_limit < 1 ? 0 : (int) (100 * $this->pms->totalArchive / $this->user->g_pm_limit),
],
],
'pm-sp2' => [null, null],
];
return $nav;
}
/**
* Возвращает массив хлебных крошек
* Заполняет массив титула страницы
*/
protected function crumbs(/* mixed */ ...$crumbs): array
{
$pms = $this->pms;
$action = $this->args['action'] ?? ($this->user->u_pm_num_new > 0 ? Cnst::ACTION_NEW : Cnst::ACTION_CURRENT);
$viewArea = false;
switch ($action) {
case Cnst::ACTION_NEW:
case Cnst::ACTION_CURRENT:
case Cnst::ACTION_ARCHIVE:
case Cnst::ACTION_SEND:
case Cnst::ACTION_TOPIC:
case Cnst::ACTION_POST:
$viewArea = true;
break;
case Cnst::ACTION_DELETE:
case Cnst::ACTION_EDIT:
case Cnst::ACTION_BLOCK:
case Cnst::ACTION_CONFIG:
default:
$crumbs[] = 'unknown';
}
if ($viewArea) {
if (null !== $pms->second) {
if (
\is_int($pms->second)
&& ($user = $this->c->users->load($pms->second)) instanceof User
&& ! $user->isGuest
) {
$name = $user->username;
} else {
$name = $pms->second;
}
switch ($pms->area) {
case Cnst::ACTION_NEW: $m = ['New messages with %s', $name]; break;
case Cnst::ACTION_CURRENT: $m = ['My talks with %s', $name]; break;
case Cnst::ACTION_ARCHIVE: $m = ['Archive messages with %s', $name]; break;
}
} else {
if ($this->targetUser instanceof User) {
$crumbs[] = [
$this->c->Router->link(
'PMAction',
[
'second' => $this->targetUser->id,
'action' => $pms->area,
]
),
__(['"%s"', $this->targetUser->username]),
];
}
switch ($pms->area) {
case Cnst::ACTION_NEW: $m = 'New messages'; break;
case Cnst::ACTION_CURRENT: $m = 'My talks'; break;
case Cnst::ACTION_ARCHIVE: $m = 'Archive messages'; break;
}
}
$crumbs[] = [
$this->c->Router->link(
'PMAction',
[
'second' => $pms->second,
'action' => $pms->area,
]
),
__($m),
];
if (null === $this->title) {
$this->title = $m;
}
}
$crumbs[] = [$this->c->Router->link('PM'), __('PM')];
return parent::crumbs(...$crumbs);
}
}

View file

@ -0,0 +1,204 @@
<?php
/**
* This file is part of the ForkBB <https://github.com/forkbb>.
*
* @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
* @license The MIT License (MIT)
*/
declare(strict_types=1);
namespace ForkBB\Models\Pages\PM;
use ForkBB\Core\Validator;
use ForkBB\Models\Page;
use ForkBB\Models\Pages\PM\AbstractPM;
use ForkBB\Models\Pages\PostFormTrait;
use ForkBB\Models\Pages\PostValidatorTrait;
use ForkBB\Models\PM\Cnst;
use ForkBB\Models\PM\PPost;
use ForkBB\Models\PM\PTopic;
use InvalidArgumentException;
use function \ForkBB\__;
class PMPost extends AbstractPM
{
use PostFormTrait;
use PostValidatorTrait;
/**
* Создание новой приватной темы или сообщения
*/
public function post(array $args, string $method): Page
{
$this->args = $args;
$quote = null;
if (
isset($args['more2'])
&& '' !== \trim($args['more2'], '1234567890')
) {
$topic = null;
$hash = $args['more2'];
$temp = $args;
unset($temp['more2']);
if (! $this->c->Csrf->verify($hash, 'PMAction', $temp)) {
return $this->c->Message->message($this->c->Csrf->getError());
}
$this->targetUser = $this->c->users->load($args['more1']);
$this->newTopic = true;
$this->formTitle = 'New PT title';
$this->pmCrumbs[] = [
$this->c->Router->link('PMAction', $args),
__('New dialogue'),
];
} elseif ($this->pms->accessTopic($args['more1'])) {
$topic = $this->pms->load(Cnst::PTOPIC, $args['more1']);
if (isset($args['more2'])) {
$quote = (int) $args['more2'];
}
$this->targetUser = $topic->ztUser;
$this->pms->area = $this->pms->inArea($topic);
$this->newTopic = false;
$this->formTitle = 'New PM title';
$this->pmCrumbs[] = [
$this->c->Router->link('PMAction', $args),
__('New message'),
];
$this->pmCrumbs[] = $topic;
} else {
return $this->c->Message->message('Not Found', true, 404);
}
$this->c->Lang->load('post');
if ('POST' === $method) {
$v = $this->messageValidatorPM(null, 'PMAction', $args, false, $this->newTopic);
if (
$v->validation($_POST)
&& null === $v->preview
&& (
null !== $v->submit
|| null !== $v->archive
)
) {
return $this->endPost($topic, $v);
}
$this->fIswev = $v->getErrors();
$args['_vars'] = $v->getData();
if (
null !== $v->preview
&& empty($this->fIswev)
) {
$this->previewHtml = $this->c->censorship->censor(
$this->c->Parser->parseMessage(null, (bool) $v->hide_smilies)
);
}
} elseif ($quote) {
$quote = $this->pms->load(Cnst::PPOST, $quote);
if (
! $quote instanceof PPost
|| $topic !== $quote->parent
) {
return $this->c->Message->message('Bad request');
}
$args['_vars'] = [
'message' => "[quote=\"{$quote->poster}\"]{$quote->message}[/quote]",
];
unset($args['more2']);
}
$this->pmIndex = $this->pms->area;
$this->nameTpl = 'pm/post';
$this->form = $this->messageFormPM(null, 'PMAction', $args, false, $this->newTopic, false);
$this->posts = $this->newTopic ? null : $topic->review();
$this->postsTitle = 'Topic review';
return $this;
}
protected function messageFormPM(?Model $model, string $marker, array $args, bool $edit, bool $first, bool $quick): array
{
$form = $this->messageForm($model, $marker, $args, $edit, $first, $quick);
if ($this->newTopic) {
$form['btns']['archive'] = [
'type' => 'submit',
'value' => __('Archive Send later'),
];
} elseif (Cnst::ACTION_ARCHIVE === $this->pmIndex) {
$form['btns']['submit']['value'] = __('Save');
}
return $form;
}
protected function messageValidatorPM(?Model $model, string $marker, array $args, bool $edit, bool $first): Validator
{
$v = $this->messageValidator($model, $marker, $args, $edit, $first)
->addRules([
'archive' => $this->newTopic ? 'string' : 'absent',
'message' => 'required|string:trim|max:65535 bytes|check_message',
]);
return $v;
}
/**
* Создание приватной темы/сообщения
*/
protected function endPost(?PTopic $topic, Validator $v): Page
{
$now = \time();
if (! $topic instanceof PTopic) {
$topic = $this->pms->create(Cnst::PTOPIC);
$topic->subject = $v->subject;
$topic->sender = $this->user;
$topic->recipient = $this->targetUser;
$topic->status = null !== $v->archive ? Cnst::PT_ARCHIVE : Cnst::PT_NORMAL;
$this->pms->insert(Cnst::PTOPIC, $topic);
}
$post = $this->pms->create(Cnst::PPOST);
$post->user = $this->user;
$post->poster_ip = $this->user->ip;
$post->message = $v->message;
$post->hide_smilies = $v->hide_smilies ? 1 : 0;
$post->posted = $now;
$post->topic_id = $topic->id;
$this->pms->insert(Cnst::PPOST, $post);
if ($this->newTopic) {
$topic->first_post_id = $post->id;
}
$this->user->u_pm_last_post = $now;
$this->pms->update(Cnst::PTOPIC, $topic->calcStat());
$this->pms->updateFromPTopics(true, $topic);
if (null !== $v->archive) {
$message = 'PM to archive Redirect';
} elseif ($this->newTopic) {
$message = 'PM created Redirect';
} else {
$message = 'PM sent Redirect';
}
return $this->c->Redirect->url($post->link)->message($message);
}
}

View file

@ -0,0 +1,133 @@
<?php
/**
* This file is part of the ForkBB <https://github.com/forkbb>.
*
* @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
* @license The MIT License (MIT)
*/
declare(strict_types=1);
namespace ForkBB\Models\Pages\PM;
use ForkBB\Models\Page;
use ForkBB\Models\Pages\PM\AbstractPM;
use ForkBB\Models\Pages\PostFormTrait;
use ForkBB\Models\PM\Cnst;
use ForkBB\Models\PM\PPost;
use ForkBB\Models\PM\PTopic;
use function \ForkBB\__;
class PMTopic extends AbstractPM
{
use PostFormTrait;
/**
* Отображает приватный диалог по номеру поста
*/
public function post(array $args, string $method): Page
{
if (
! isset($args['more1'])
|| isset($args['more2'])
) {
return $this->c->Message->message('Bad request');
}
$post = $this->pms->load(Cnst::PPOST, $args['more1']);
if (! $post instanceof PPost) {
return $this->c->Message->message('Not Found', true, 404);
}
$this->model = $post->parent;
$this->model->calcPage($post->id);
return $this->view($args, $method);
}
/**
* Отображает приватный диалог по его номеру
*/
public function topic(array $args, string $method): Page
{
if (! isset($args['more1'])) {
return $this->c->Message->message('Bad request');
}
$this->model = $this->pms->load(Cnst::PTOPIC, $args['more1']);
if (! $this->model instanceof PTopic) {
return $this->c->Message->message('Not Found', true, 404);
}
if (! isset($args['more2'])) {
$this->model->page = 1;
} elseif ('new' === $args['more2']) {
$new = $this->model->firstNew;
if ($new > 0) {
$new = $this->pms->load(Cnst::PPOST, $new);
}
if ($new instanceof PPost) {
return $this->c->Redirect->url($new->link);
} else {
return $this->c->Redirect->url($this->model->linkLast);
}
} elseif ('' === \trim($args['more2'], '1234567890')) {
$this->model->page = (int) $args['more2'];
} else {
return $this->c->Message->message('Not Found', true, 404);
}
return $this->view($args, $method);
}
/**
* Подготовка данных для шаблона
*/
protected function view(array $args, string $method): Page
{
if (! $this->model->hasPage()) {
return $this->c->Message->message('Not Found', true, 404);
}
$this->posts = $this->model->pageData();
if (
empty($this->posts)
&& $this->model->page > 1
) {
return $this->c->Redirect->url($this->model->link);
}
$this->c->Lang->load('topic');
$this->args = $args;
$this->targetUser = $this->model->ztUser;
$this->pms->area = $this->pms->inArea($this->model);
$this->pmIndex = $this->pms->area;
$this->nameTpl = 'pm/topic';
$this->pmCrumbs[] = $this->model;
if (
$this->model->canReply
&& '1' == $this->c->config->o_quickpost
) {
$form = $this->messageForm(null, 'PMAction', $this->model->dataReply, false, false, true);
if (Cnst::ACTION_ARCHIVE === $this->pmIndex) {
$form['btns']['submit']['value'] = __('Save');
}
$this->form = $form;
}
$this->model->updateVisit();
return $this;
}
}

View file

@ -0,0 +1,45 @@
<?php
/**
* This file is part of the ForkBB <https://github.com/forkbb>.
*
* @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
* @license The MIT License (MIT)
*/
declare(strict_types=1);
namespace ForkBB\Models\Pages\PM;
use ForkBB\Core\Validator;
use ForkBB\Models\Page;
use ForkBB\Models\Pages\PM\AbstractPM;
use ForkBB\Models\Forum\Model as Forum;
use ForkBB\Models\User\Model as User;
use InvalidArgumentException;
use function \ForkBB\__;
class PMView extends AbstractPM
{
/**
* Списки новых, текущих и архивных приватных топиков
*/
public function view(array $args, string $method): Page
{
$this->args = $args;
$this->pms->page = $args['more1'] ?? 1;
if (
isset($args['more2'])
|| ! $this->pms->hasPage()
) {
return $this->c->Message->message('Not Found', true, 404);
}
$this->pmIndex = $this->pms->area;
$this->nameTpl = 'pm/view';
$this->pmList = $this->pms->pmListCurPage();
$this->pagination = $this->pms->pagination;
return $this;
}
}