662 lines
23 KiB
PHP
662 lines
23 KiB
PHP
<?php
|
|
namespace Misuzu\Messages;
|
|
|
|
use stdClass;
|
|
use InvalidArgumentException;
|
|
use RuntimeException;
|
|
use Index\XString;
|
|
use Index\Config\Config;
|
|
use Index\Colour\Colour;
|
|
use Index\Http\{FormHttpContent,HttpRequest,HttpResponseBuilder};
|
|
use Index\Http\Content\FormContent;
|
|
use Index\Http\Routing\Processors\{After,Before};
|
|
use Index\Http\Routing\Routes\{ExactRoute,PatternRoute};
|
|
use Index\Urls\{UrlFormat,UrlRegistry,UrlSource,UrlSourceCommon};
|
|
use Misuzu\{Misuzu,Pagination,Perm,Template};
|
|
use Misuzu\Auth\AuthInfo;
|
|
use Misuzu\Parsers\TextFormat;
|
|
use Misuzu\Perms\PermissionsData;
|
|
use Misuzu\Routing\{HandlerRoles,RouteHandler,RouteHandlerCommon};
|
|
use Misuzu\Users\{UsersContext,UserInfo};
|
|
|
|
#[HandlerRoles('main')]
|
|
class MessagesRoutes implements RouteHandler, UrlSource {
|
|
use RouteHandlerCommon, UrlSourceCommon;
|
|
|
|
public const FOLDER_META = [
|
|
'inbox' => [ 'title' => 'Inbox', 'icon' => 'fas fa-inbox fa-fw' ],
|
|
'drafts' => [ 'title' => 'Drafts', 'icon' => 'fas fa-pencil-alt fa-fw' ],
|
|
'sent' => [ 'title' => 'Sent', 'icon' => 'fas fa-paper-plane fa-fw' ],
|
|
'trash' => [ 'title' => 'Trash', 'icon' => 'fas fa-trash-alt fa-fw' ],
|
|
];
|
|
|
|
public function __construct(
|
|
private Config $config,
|
|
private UrlRegistry $urls,
|
|
private AuthInfo $authInfo,
|
|
private MessagesContext $msgsCtx,
|
|
private UsersContext $usersCtx,
|
|
private PermissionsData $perms,
|
|
) {}
|
|
|
|
private bool $canSendMessages {
|
|
get {
|
|
return $this->authInfo->getPerms('global')->check(Perm::G_MESSAGES_SEND)
|
|
&& !$this->usersCtx->hasActiveBan($this->authInfo->userInfo);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return object{
|
|
* info: MessageInfo,
|
|
* author_info: UserInfo,
|
|
* author_colour: Colour,
|
|
* recipient_info: UserInfo,
|
|
* recipient_colour: Colour
|
|
* }
|
|
*/
|
|
private function populateMessage(MessageInfo $messageInfo): object {
|
|
$message = new stdClass;
|
|
|
|
$message->info = $messageInfo;
|
|
$message->author_info = $messageInfo->authorId !== null ? $this->usersCtx->getUserInfo($messageInfo->authorId, 'id') : null;
|
|
$message->author_colour = $this->usersCtx->getUserColour($message->author_info);
|
|
$message->recipient_info = $messageInfo->recipientId !== null ? $this->usersCtx->getUserInfo($messageInfo->recipientId, 'id') : null;
|
|
$message->recipient_colour = $this->usersCtx->getUserColour($message->recipient_info);
|
|
|
|
return $message;
|
|
}
|
|
|
|
#[ExactRoute('GET', '/messages')]
|
|
#[Before('authz:cookie', required: true)]
|
|
#[Before('authz:private')]
|
|
#[Before('authz:perm', category: 'global', perm: Perm::G_MESSAGES_VIEW)]
|
|
#[UrlFormat('messages-index', '/messages', ['folder' => '<folder>', 'page' => '<page>'])]
|
|
public function getIndex(HttpRequest $request, string $folderName = ''): int|string {
|
|
$folderName = (string)$request->getParam('folder');
|
|
if($folderName === '')
|
|
$folderName = 'inbox';
|
|
|
|
if(!array_key_exists($folderName, self::FOLDER_META))
|
|
return 404;
|
|
|
|
$folderInbox = $folderName === 'inbox';
|
|
$folderDrafts = $folderName === 'drafts';
|
|
$folderSent = $folderName === 'sent';
|
|
$folderTrash = $folderName === 'trash';
|
|
|
|
$selfInfo = $this->authInfo->userInfo;
|
|
$msgsDb = $this->msgsCtx->database;
|
|
|
|
$authorInfo = !$folderTrash && $folderSent ? $selfInfo : null;
|
|
$recipientInfo = !$folderTrash && $folderInbox ? $selfInfo : null;
|
|
$sent = $folderTrash ? null : !$folderDrafts;
|
|
$deleted = $folderTrash;
|
|
|
|
$pagination = Pagination::fromRequest($request, $msgsDb->countMessages(
|
|
ownerInfo: $selfInfo,
|
|
authorInfo: $authorInfo,
|
|
recipientInfo: $recipientInfo,
|
|
sent: $sent,
|
|
deleted: $deleted,
|
|
), 50);
|
|
|
|
$messageInfos = $msgsDb->getMessages(
|
|
ownerInfo: $selfInfo,
|
|
authorInfo: $authorInfo,
|
|
recipientInfo: $recipientInfo,
|
|
sent: $sent,
|
|
deleted: $deleted,
|
|
pagination: $pagination,
|
|
);
|
|
|
|
$messages = [];
|
|
foreach($messageInfos as $messageInfo)
|
|
$messages[] = $this->populateMessage($messageInfo);
|
|
|
|
return Template::renderRaw('messages.index', [
|
|
'can_send_messages' => $this->canSendMessages,
|
|
'folder_name' => $folderName,
|
|
'folder_meta' => self::FOLDER_META,
|
|
'folder_messages' => $messages,
|
|
'folder_pagination' => $pagination,
|
|
]);
|
|
}
|
|
|
|
/** @return array{unread: int} */
|
|
#[ExactRoute('GET', '/messages/stats')]
|
|
#[Before('authz:cookie', type: 'json', required: true)]
|
|
#[Before('authz:private', type: 'json')]
|
|
#[Before('authz:perm', type: 'json', category: 'global', perm: Perm::G_MESSAGES_VIEW)]
|
|
#[UrlFormat('messages-stats', '/messages/stats')]
|
|
public function getStats(): array {
|
|
$selfInfo = $this->authInfo->userInfo;
|
|
$msgsDb = $this->msgsCtx->database;
|
|
|
|
return [
|
|
'unread' => $msgsDb->countMessages(
|
|
ownerInfo: $selfInfo,
|
|
recipientInfo: $selfInfo,
|
|
sent: true,
|
|
deleted: false,
|
|
read: false,
|
|
),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return int|array{avatar: string}|array{
|
|
* id: string,
|
|
* name: string,
|
|
* ban: bool,
|
|
* avatar: string
|
|
* }
|
|
*/
|
|
#[ExactRoute('POST', '/messages/recipient')]
|
|
#[Before('authz:cookie', type: 'json', required: true)]
|
|
#[Before('authz:private', type: 'json')]
|
|
#[Before('authz:perm', type: 'json', category: 'global', perm: Perm::G_MESSAGES_VIEW)]
|
|
#[Before('csrf:header', type: 'json')]
|
|
#[Before('input:urlencoded')]
|
|
#[UrlFormat('messages-recipient', '/messages/recipient')]
|
|
public function postRecipient(FormContent $content): int|array {
|
|
if(!$this->canSendMessages)
|
|
return 403;
|
|
|
|
$name = trim((string)$content->getParam('name'));
|
|
|
|
// flappy hacks
|
|
if(str_starts_with(mb_strtolower($name), 'flappyzor'))
|
|
$name = 14;
|
|
|
|
$userInfo = null;
|
|
if(!empty($name))
|
|
try {
|
|
$userInfo = $this->usersCtx->getUserInfo($name, 'messaging');
|
|
} catch(InvalidArgumentException $ex) {
|
|
} catch(RuntimeException $ex) {}
|
|
|
|
if($userInfo === null)
|
|
return [
|
|
'avatar' => $this->urls->format('user-avatar', [
|
|
'res' => 200,
|
|
]),
|
|
];
|
|
|
|
return [
|
|
'id' => $userInfo->id,
|
|
'name' => $userInfo->name,
|
|
'ban' => $this->usersCtx->hasActiveBan($userInfo),
|
|
'avatar' => $this->urls->format('user-avatar', [
|
|
'user' => $userInfo->id,
|
|
'res' => 200,
|
|
]),
|
|
];
|
|
}
|
|
|
|
#[ExactRoute('GET', '/messages/compose')]
|
|
#[Before('authz:cookie', required: true)]
|
|
#[Before('authz:private')]
|
|
#[Before('authz:perm', category: 'global', perm: Perm::G_MESSAGES_VIEW)]
|
|
#[UrlFormat('messages-compose', '/messages/compose', ['recipient' => '<recipient>'])]
|
|
public function getEditor(HttpRequest $request): int|string {
|
|
if(!$this->canSendMessages)
|
|
return 403;
|
|
|
|
return Template::renderRaw('messages.compose', [
|
|
'recipient' => (string)$request->getParam('recipient'),
|
|
]);
|
|
}
|
|
|
|
#[PatternRoute('GET', '/messages/([A-Za-z0-9]+)')]
|
|
#[Before('authz:cookie', required: true)]
|
|
#[Before('authz:private')]
|
|
#[Before('authz:perm', category: 'global', perm: Perm::G_MESSAGES_VIEW)]
|
|
#[UrlFormat('messages-view', '/messages/<message>')]
|
|
public function getView(string $messageId): int|string {
|
|
if(strlen($messageId) !== 8)
|
|
return 404;
|
|
|
|
$selfInfo = $this->authInfo->userInfo;
|
|
$msgsDb = $this->msgsCtx->database;
|
|
|
|
try {
|
|
$messageInfo = $msgsDb->getMessageInfo($selfInfo, $messageId);
|
|
} catch(RuntimeException $ex) {
|
|
return 404;
|
|
}
|
|
|
|
if(!$messageInfo->read)
|
|
$msgsDb->updateMessage(
|
|
ownerInfo: $selfInfo,
|
|
messageInfo: $messageInfo,
|
|
readAt: time(),
|
|
);
|
|
|
|
$message = $this->populateMessage($messageInfo);
|
|
|
|
$replyTo = null;
|
|
if($messageInfo->replyToId !== null) {
|
|
try {
|
|
$replyTo = $this->populateMessage(
|
|
$msgsDb->getMessageInfo($selfInfo, $messageInfo, true)
|
|
);
|
|
} catch(RuntimeException $ex) {}
|
|
}
|
|
|
|
$repliesForInfos = $msgsDb->getMessages(
|
|
ownerInfo: $selfInfo,
|
|
repliesFor: $messageInfo,
|
|
deleted: false,
|
|
);
|
|
|
|
$draftInfo = null;
|
|
$repliesFor = [];
|
|
foreach($repliesForInfos as $repliesForInfo) {
|
|
$repliesFor[] = $this->populateMessage($repliesForInfo);
|
|
|
|
if(!$repliesForInfo->sent && $draftInfo === null)
|
|
$draftInfo = $repliesForInfo;
|
|
}
|
|
|
|
return Template::renderRaw('messages.thread', [
|
|
'can_send_messages' => $this->canSendMessages,
|
|
'self_info' => $selfInfo,
|
|
'reply_to' => $replyTo,
|
|
'message' => $message,
|
|
'draft_info' => $draftInfo,
|
|
'replies_for' => $repliesFor,
|
|
]);
|
|
}
|
|
|
|
/** @return ?array{error: array{name: string, text: string}} */
|
|
private function checkCanReceiveMessages(UserInfo|string $userInfo): ?array {
|
|
$globalPerms = $this->perms->getPermissions('global', $userInfo);
|
|
if(!$globalPerms->check(Perm::G_MESSAGES_VIEW))
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:recipient_cannot_recv',
|
|
'text' => 'This person is not allowed to receive messages.',
|
|
],
|
|
];
|
|
|
|
return null;
|
|
}
|
|
|
|
/** @return ?array{error: array{name: string, text: string, args?: scalar[]}} */
|
|
private function checkMessageFields(string $title, string $body, ?TextFormat $format): ?array {
|
|
if($format === null)
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:invalid_format',
|
|
'text' => 'Invalid format selected.',
|
|
],
|
|
];
|
|
|
|
$lengths = $this->config->getValues([
|
|
['title.minLength:i', 1],
|
|
['title.maxLength:i', 200],
|
|
['body.minLength:i', 1],
|
|
['body.maxLength:i', 60000],
|
|
]);
|
|
|
|
$titleLength = mb_strlen(trim($title));
|
|
|
|
if($titleLength < $lengths['title.minLength'])
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:title_too_short',
|
|
'args' => [$lengths['title.minLength'], $titleLength],
|
|
'text' => sprintf('Title may not be shorter than %d characters. You entered %d characters.', $lengths['title.minLength'], $titleLength),
|
|
],
|
|
];
|
|
|
|
if($titleLength > $lengths['title.maxLength'])
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:title_too_long',
|
|
'args' => [$lengths['title.maxLength'], $titleLength],
|
|
'text' => sprintf('Title may not be longer than %d characters. You entered %d characters.', $lengths['title.maxLength'], $titleLength),
|
|
],
|
|
];
|
|
|
|
$bodyLength = mb_strlen(trim($body));
|
|
|
|
if($bodyLength < $lengths['body.minLength'])
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:body_too_short',
|
|
'args' => [$lengths['body.minLength'], $bodyLength],
|
|
'text' => sprintf('Message may not be shorter than %d characters. You entered %d characters.', $lengths['body.minLength'], $bodyLength),
|
|
],
|
|
];
|
|
|
|
if($bodyLength > $lengths['body.maxLength'])
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:body_too_long',
|
|
'args' => [$lengths['body.maxLength'], $bodyLength],
|
|
'text' => sprintf('Message may not be longer than %d characters. You entered %d characters.', $lengths['body.maxLength'], $bodyLength),
|
|
],
|
|
];
|
|
|
|
return null;
|
|
}
|
|
|
|
/** @return int|array{error: array{name: string, text: string}}|array{id: string, url: string} */
|
|
#[ExactRoute('POST', '/messages/create')]
|
|
#[Before('authz:cookie', type: 'json', required: true)]
|
|
#[Before('authz:private', type: 'json')]
|
|
#[Before('authz:perm', type: 'json', category: 'global', perm: Perm::G_MESSAGES_VIEW)]
|
|
#[Before('csrf:header', type: 'json')]
|
|
#[Before('input:multipart')]
|
|
#[UrlFormat('messages-create', '/messages/create')]
|
|
public function postCreate(FormContent $content): int|array {
|
|
if(!$this->canSendMessages)
|
|
return 403;
|
|
|
|
$recipient = (string)$content->getParam('recipient');
|
|
$replyTo = (string)$content->getParam('reply');
|
|
$title = (string)$content->getParam('title');
|
|
$body = (string)$content->getParam('body');
|
|
$format = TextFormat::tryFrom((string)$content->getParam('format'));
|
|
$draft = !empty($content->getParam('draft'));
|
|
|
|
$error = $this->checkMessageFields($title, $body, $format);
|
|
if($error !== null)
|
|
return $error;
|
|
|
|
$selfInfo = $this->authInfo->userInfo;
|
|
$msgsDb = $this->msgsCtx->database;
|
|
|
|
try {
|
|
$recipientInfo = $this->usersCtx->getUserInfo($recipient, 'messaging');
|
|
} catch(InvalidArgumentException $ex) {
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:recipient_invalid',
|
|
'text' => 'Name of the recipient was incorrectly formatted.',
|
|
],
|
|
];
|
|
} catch(RuntimeException $ex) {
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:recipient_not_found',
|
|
'text' => 'Recipient does not exist.',
|
|
],
|
|
];
|
|
}
|
|
|
|
$error = $this->checkCanReceiveMessages($recipientInfo);
|
|
if($error !== null)
|
|
return $error;
|
|
|
|
$replyToInfo = null;
|
|
if(!empty($replyTo)) {
|
|
try {
|
|
$replyToInfo = $msgsDb->getMessageInfo($selfInfo, $replyTo);
|
|
} catch(RuntimeException $ex) {
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:reply_not_found',
|
|
'text' => 'The message you are trying to reply to does not exist.',
|
|
],
|
|
];
|
|
}
|
|
|
|
if(!$replyToInfo->sent)
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:draft_reply',
|
|
'text' => 'You cannot reply to a draft.',
|
|
],
|
|
];
|
|
}
|
|
|
|
$msgId = XString::random(8);
|
|
$sentAt = $draft ? null : time();
|
|
|
|
// own copy
|
|
$msgsDb->createMessage(
|
|
messageId: $msgId,
|
|
ownerInfo: $selfInfo,
|
|
authorInfo: $selfInfo,
|
|
recipientInfo: $recipientInfo,
|
|
title: $title,
|
|
body: $body,
|
|
bodyFormat: $format,
|
|
replyTo: $replyToInfo,
|
|
sentAt: $sentAt
|
|
);
|
|
|
|
// recipient copy
|
|
if($sentAt !== null && $recipientInfo->id !== $selfInfo->id)
|
|
$msgsDb->createMessage(
|
|
messageId: $msgId,
|
|
ownerInfo: $recipientInfo,
|
|
authorInfo: $selfInfo,
|
|
recipientInfo: $recipientInfo,
|
|
title: $title,
|
|
body: $body,
|
|
bodyFormat: $format,
|
|
replyTo: $replyToInfo,
|
|
sentAt: $sentAt
|
|
);
|
|
|
|
return [
|
|
'id' => $msgId,
|
|
'url' => $this->urls->format('messages-view', ['message' => $msgId]),
|
|
];
|
|
}
|
|
|
|
/** @return int|array{error: array{name: string, text: string}}|array{id: string, url: string} */
|
|
#[PatternRoute('PATCH', '/messages/([A-Za-z0-9]+)')]
|
|
#[Before('authz:cookie', type: 'json', required: true)]
|
|
#[Before('authz:private', type: 'json')]
|
|
#[Before('authz:perm', type: 'json', category: 'global', perm: Perm::G_MESSAGES_VIEW)]
|
|
#[Before('csrf:header', type: 'json')]
|
|
#[Before('input:multipart')]
|
|
#[UrlFormat('messages-update', '/messages/<message>')]
|
|
public function patchUpdate(FormContent $content, string $messageId): int|array {
|
|
if(!$this->canSendMessages)
|
|
return 403;
|
|
|
|
$title = (string)$content->getParam('title');
|
|
$body = (string)$content->getParam('body');
|
|
$format = TextFormat::tryFrom((string)$content->getParam('format'));
|
|
$draft = !empty($content->getParam('draft'));
|
|
|
|
$error = $this->checkMessageFields($title, $body, $format);
|
|
if($error !== null)
|
|
return $error;
|
|
|
|
$selfInfo = $this->authInfo->userInfo;
|
|
$msgsDb = $this->msgsCtx->database;
|
|
|
|
try {
|
|
$messageInfo = $msgsDb->getMessageInfo($selfInfo, $messageId);
|
|
} catch(RuntimeException $ex) {
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:edit_not_found',
|
|
'text' => 'The message you are trying to edit does not exist.',
|
|
],
|
|
];
|
|
}
|
|
|
|
if($messageInfo->authorId === null || $messageInfo->authorId !== $selfInfo->id)
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:not_author',
|
|
'text' => 'You are not the author of this message.',
|
|
],
|
|
];
|
|
|
|
if($messageInfo->recipientId === null)
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:recipient_gone',
|
|
'text' => 'The recipient of this message no longer exists, it cannot be sent or edited.',
|
|
],
|
|
];
|
|
|
|
if($messageInfo->sent)
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:not_draft',
|
|
'text' => 'You cannot edit a message that has already been sent.',
|
|
],
|
|
];
|
|
|
|
$error = $this->checkCanReceiveMessages($messageInfo->recipientId);
|
|
if($error !== null)
|
|
return $error;
|
|
|
|
$sentAt = $draft ? null : time();
|
|
|
|
$msgsDb->updateMessage(
|
|
ownerInfo: $selfInfo,
|
|
messageInfo: $messageInfo,
|
|
title: $title,
|
|
body: $body,
|
|
bodyFormat: $format,
|
|
sentAt: $sentAt,
|
|
);
|
|
|
|
// recipient copy
|
|
if($sentAt !== null && $messageInfo->recipientId !== $selfInfo->id)
|
|
$msgsDb->createMessage(
|
|
messageId: $messageId,
|
|
ownerInfo: $messageInfo->recipientId,
|
|
authorInfo: $selfInfo,
|
|
recipientInfo: $messageInfo->recipientId,
|
|
title: $title,
|
|
body: $body,
|
|
bodyFormat: $format,
|
|
replyTo: $messageInfo->replyToId,
|
|
sentAt: $sentAt
|
|
);
|
|
|
|
return [
|
|
'id' => $messageId,
|
|
'url' => $this->urls->format('messages-view', ['message' => $messageId]),
|
|
];
|
|
}
|
|
|
|
/** @return int|array{error: array{name: string, text: string}}|scalar[] */
|
|
#[ExactRoute('POST', '/messages/mark')]
|
|
#[Before('authz:cookie', type: 'json', required: true)]
|
|
#[Before('authz:private', type: 'json')]
|
|
#[Before('authz:perm', type: 'json', category: 'global', perm: Perm::G_MESSAGES_VIEW)]
|
|
#[Before('csrf:header', type: 'json')]
|
|
#[Before('input:urlencoded')]
|
|
#[UrlFormat('messages-mark', '/messages/mark')]
|
|
public function postMark(FormContent $content): int|array {
|
|
$type = (string)$content->getParam('type');
|
|
$messages = explode(',', (string)$content->getParam('messages'));
|
|
|
|
if($type !== 'read' && $type !== 'unread')
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:unsupported_mark',
|
|
'text' => 'Attempting to mark message with an unsupported state.',
|
|
],
|
|
];
|
|
|
|
$selfInfo = $this->authInfo->userInfo;
|
|
$msgsDb = $this->msgsCtx->database;
|
|
|
|
foreach($messages as $messageId)
|
|
$msgsDb->updateMessage(
|
|
ownerInfo: $selfInfo,
|
|
messageInfo: $messageId,
|
|
readAt: $type === 'read' ? time() : null,
|
|
);
|
|
|
|
return [];
|
|
}
|
|
|
|
/** @return int|array{error: array{name: string, text: string}}|scalar[] */
|
|
#[ExactRoute('POST', '/messages/delete')]
|
|
#[Before('authz:cookie', type: 'json', required: true)]
|
|
#[Before('authz:private', type: 'json')]
|
|
#[Before('authz:perm', type: 'json', category: 'global', perm: Perm::G_MESSAGES_VIEW)]
|
|
#[Before('csrf:header', type: 'json')]
|
|
#[Before('input:urlencoded')]
|
|
#[UrlFormat('messages-delete', '/messages/delete')]
|
|
public function postDelete(FormContent $content): int|array {
|
|
$messages = (string)$content->getParam('messages');
|
|
if($messages === '')
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:empty',
|
|
'text' => 'No messages were supplied.',
|
|
],
|
|
];
|
|
|
|
$messages = explode(',', $messages);
|
|
|
|
$this->msgsCtx->database->deleteMessages(
|
|
$this->authInfo->userInfo,
|
|
$messages
|
|
);
|
|
|
|
return [];
|
|
}
|
|
|
|
/** @return int|array{error: array{name: string, text: string}}|scalar[] */
|
|
#[ExactRoute('POST', '/messages/restore')]
|
|
#[Before('authz:cookie', type: 'json', required: true)]
|
|
#[Before('authz:private', type: 'json')]
|
|
#[Before('authz:perm', type: 'json', category: 'global', perm: Perm::G_MESSAGES_VIEW)]
|
|
#[Before('csrf:header', type: 'json')]
|
|
#[Before('input:urlencoded')]
|
|
#[UrlFormat('messages-restore', '/messages/restore')]
|
|
public function postRestore(FormContent $content) {
|
|
$messages = (string)$content->getParam('messages');
|
|
if($messages === '')
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:empty',
|
|
'text' => 'No messages were supplied.',
|
|
],
|
|
];
|
|
|
|
$messages = explode(',', $messages);
|
|
|
|
$this->msgsCtx->database->restoreMessages(
|
|
$this->authInfo->userInfo,
|
|
$messages
|
|
);
|
|
|
|
return [];
|
|
}
|
|
|
|
/** @return int|array{error: array{name: string, text: string}}|scalar[] */
|
|
#[ExactRoute('POST', '/messages/nuke')]
|
|
#[Before('authz:cookie', type: 'json', required: true)]
|
|
#[Before('authz:private', type: 'json')]
|
|
#[Before('authz:perm', type: 'json', category: 'global', perm: Perm::G_MESSAGES_VIEW)]
|
|
#[Before('csrf:header', type: 'json')]
|
|
#[Before('input:urlencoded')]
|
|
#[UrlFormat('messages-nuke', '/messages/nuke')]
|
|
public function postNuke(FormContent $content) {
|
|
$messages = (string)$content->getParam('messages');
|
|
if($messages === '')
|
|
return [
|
|
'error' => [
|
|
'name' => 'msgs:empty',
|
|
'text' => 'No messages were supplied.',
|
|
],
|
|
];
|
|
|
|
$messages = explode(',', $messages);
|
|
|
|
$this->msgsCtx->database->nukeMessages(
|
|
$this->authInfo->userInfo,
|
|
$messages
|
|
);
|
|
|
|
return [];
|
|
}
|
|
}
|