diff --git a/VKAPI/Handlers/Messages.php b/VKAPI/Handlers/Messages.php index b3c4c1b83..df654ccb1 100644 --- a/VKAPI/Handlers/Messages.php +++ b/VKAPI/Handlers/Messages.php @@ -141,7 +141,6 @@ public function send( } elseif (!empty($attachment)) { $attachs = parseAttachments($attachment); - # Работают только фотки, остальное просто не будет отображаться. if (sizeof($attachs) >= 10) { $this->fail(15, "Too many attachments"); } diff --git a/Web/Models/Entities/Message.php b/Web/Models/Entities/Message.php index 1d3364c5b..b435fc691 100644 --- a/Web/Models/Entities/Message.php +++ b/Web/Models/Entities/Message.php @@ -7,7 +7,7 @@ use Chandler\Database\DatabaseConnection; use openvk\Web\Models\Repositories\Clubs; use openvk\Web\Models\Repositories\Users; -use openvk\Web\Models\Entities\Photo; +use openvk\Web\Models\Entities\{Photo, Video, Audio, Note, Document}; use openvk\Web\Models\RowModel; use openvk\Web\Util\DateTime; @@ -131,17 +131,77 @@ public function simplify(): array $attachments[] = [ "type" => "photo", "link" => "/photo" . $attachment->getPrettyId(), + "id" => $attachment->getPrettyId(), "photo" => [ "url" => $attachment->getURL(), "caption" => $attachment->getDescription(), ], ]; + } elseif ($attachment instanceof Video) { + if ($attachment->getType() != 1) { + $videoUrl = $attachment->getURL(); + $embedHtml = null; + } else { + $videoUrl = $attachment->getVideoDriver()->getURL(); + $embedHtml = $attachment->getVideoDriver()->getEmbed("100%"); + } + $attachments[] = [ + "type" => "video", + "link" => "/video" . $attachment->getPrettyId(), + "id" => $attachment->getOwner()->getId() . "_" . $attachment->getVirtualId(), + "video" => [ + "url" => $videoUrl, + "embed_html" => $embedHtml, + "name" => $attachment->getName(), + "length" => $attachment->getLength(), + "formatted_length" => $attachment->getFormattedLength(), + "thumbnail" => $attachment->getThumbnailURL(), + "author" => $attachment->getOwner()->getCanonicalName(), + ], + ]; + } elseif ($attachment instanceof Audio) { + $attachments[] = [ + "type" => "audio", + "link" => "/audio" . $attachment->getPrettyId(), + "audio" => [ + "name" => $attachment->getName(), + "artist" => $attachment->getPerformer(), + ], + ]; + } elseif ($attachment instanceof Note) { + $attachments[] = [ + "type" => "note", + "link" => "/note" . $attachment->getId(), + "id" => $attachment->getId(), + "note" => [ + "name" => $attachment->getName(), + ], + ]; + } elseif ($attachment instanceof Document) { + $previewData = null; + if ($attachment->hasPreview()) { + $previewData = [ + "tiny" => $attachment->getPreview()->getURLBySizeId('tiny'), + "medium" => $attachment->getPreview()->getURLBySizeId('medium'), + ]; + } + + $attachments[] = [ + "type" => "doc", + "link" => "/doc" . $attachment->getPrettyId(), + "id" => $attachment->getPrettyId(), + "document" => [ + "name" => $attachment->getName(), + "ext" => $attachment->getFileExtension(), + "size_str" => readable_filesize($attachment->getFilesize()), + "preview" => $previewData, + "pub_time" => (string) $attachment->getPublicationTime(), + ], + ]; } else { $attachments[] = [ "type" => "unknown", ]; - - # throw new \Exception("Unknown attachment type: " . get_class($attachment)); } } diff --git a/Web/Models/Entities/Photo.php b/Web/Models/Entities/Photo.php index b0ee2e83e..9ef394b7d 100644 --- a/Web/Models/Entities/Photo.php +++ b/Web/Models/Entities/Photo.php @@ -9,12 +9,15 @@ use Nette\Utils\UnknownImageFileException; use openvk\Web\Models\Entities\Album; use openvk\Web\Models\Repositories\Albums; +use openvk\Web\Models\Entities\Traits\TMessageAttachment; use Chandler\Database\DatabaseConnection as DB; use Nette\InvalidStateException as ISE; use Nette\Utils\Image; class Photo extends Media { + use TMessageAttachment; + protected $tableName = "photos"; protected $fileExtension = "jpeg"; @@ -381,12 +384,27 @@ public function toVkApiStruct(bool $photo_sizes = true, bool $extended = false): return $res; } + public function isMessagePhoto(): bool + { + return (bool) $this->getRecord()->is_message_photo; + } + public function canBeViewedBy(?User $user = null): bool { if ($this->isDeleted() || $this->getOwner()->isDeleted()) { return false; } + if ($this->isMessagePhoto()) { + if (!$user) { + return false; + } + if ($user->getId() === $this->getOwner()->getId()) { + return true; + } + return $this->isViewableByMessageParticipant($user); + } + if (!is_null($this->getAlbum())) { return $this->getAlbum()->canBeViewedBy($user); } else { diff --git a/Web/Models/Entities/Traits/TMessageAttachment.php b/Web/Models/Entities/Traits/TMessageAttachment.php new file mode 100644 index 000000000..fa0f31514 --- /dev/null +++ b/Web/Models/Entities/Traits/TMessageAttachment.php @@ -0,0 +1,45 @@ +getContext(); + $msgIds = []; + + foreach ($db->table("attachments") + ->select("target_id") + ->where("attachable_type", get_class($this)) + ->where("attachable_id", $this->getId()) + ->where("target_type", "openvk\\Web\\Models\\Entities\\Message") as $row) { + $msgIds[] = $row->target_id; + } + + if (empty($msgIds)) { + return false; + } + + return (bool) $db->table("messages") + ->where("id", $msgIds) + ->where("deleted", 0) + ->where( + "(sender_type = ? AND sender_id = ?) OR (recipient_type = ? AND recipient_id = ?)", + "openvk\\Web\\Models\\Entities\\User", + $user->getId(), + "openvk\\Web\\Models\\Entities\\User", + $user->getId() + ) + ->count("*"); + } +} diff --git a/Web/Models/Entities/Video.php b/Web/Models/Entities/Video.php index 8dbfb7a16..cb4aadb65 100644 --- a/Web/Models/Entities/Video.php +++ b/Web/Models/Entities/Video.php @@ -7,12 +7,15 @@ use openvk\Web\Util\Shell\Shell; use openvk\Web\Util\Shell\Exceptions\{ShellUnavailableException, UnknownCommandException}; use openvk\Web\Models\VideoDrivers\VideoDriver; +use openvk\Web\Models\Entities\Traits\TMessageAttachment; use Nette\InvalidStateException as ISE; define("VIDEOS_FRIENDLY_ERROR", "Uploads are disabled on this instance :<"); class Video extends Media { + use TMessageAttachment; + public const TYPE_DIRECT = 0; public const TYPE_EMBED = 1; public const TYPE_UNKNOWN = -1; @@ -339,12 +342,27 @@ public function getPageURL(): string return "/video" . $this->getPrettyId(); } + public function isMessageVideo(): bool + { + return (bool) $this->getRecord()->is_message_video; + } + public function canBeViewedBy(?User $user = null): bool { if ($this->isDeleted() || $this->getOwner()->isDeleted()) { return false; } + if ($this->isMessageVideo()) { + if (!$user) { + return false; + } + if ($user->getId() === $this->getOwner()->getId()) { + return true; + } + return $this->isViewableByMessageParticipant($user); + } + if (get_class($this->getOwner()) == "openvk\\Web\\Models\\Entities\\User") { return $this->getOwner()->canBeViewedBy($user) && $this->getOwner()->getPrivacyPermission('videos.read', $user); } else { diff --git a/Web/Models/Repositories/Photos.php b/Web/Models/Repositories/Photos.php index 4de620257..c4626e52d 100644 --- a/Web/Models/Repositories/Photos.php +++ b/Web/Models/Repositories/Photos.php @@ -52,6 +52,7 @@ public function getEveryUserPhoto(User $user, int $offset = 0, int $limit = 10): "system" => 0, "private" => 0, "anonymous" => 0, + "is_message_photo" => 0, ])->order("id DESC"); foreach ($photos->limit($limit, $offset) as $photo) { @@ -67,6 +68,7 @@ public function getUserPhotosCount(User $user) "system" => 0, "private" => 0, "anonymous" => 0, + "is_message_photo" => 0, ]); return sizeof($photos); diff --git a/Web/Models/Repositories/Videos.php b/Web/Models/Repositories/Videos.php index de8e3d95b..c7ec9e343 100644 --- a/Web/Models/Repositories/Videos.php +++ b/Web/Models/Repositories/Videos.php @@ -45,7 +45,7 @@ public function getByOwnerAndVID(int $owner, int $vId): ?Video public function getByUser(User $user, int $page = 1, ?int $perPage = null): \Traversable { $perPage ??= OPENVK_DEFAULT_PER_PAGE; - foreach ($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0])->page($page, $perPage)->order("created DESC") as $video) { + foreach ($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0, "is_message_video" => 0])->page($page, $perPage)->order("created DESC") as $video) { yield new Video($video); } } @@ -53,20 +53,20 @@ public function getByUser(User $user, int $page = 1, ?int $perPage = null): \Tra public function getByUserLimit(User $user, int $offset = 0, int $limit = 10): \Traversable { $perPage ??= OPENVK_DEFAULT_PER_PAGE; - foreach ($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0])->limit($limit, $offset)->order("created DESC") as $video) { + foreach ($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0, "is_message_video" => 0])->limit($limit, $offset)->order("created DESC") as $video) { yield new Video($video); } } public function getUserVideosCount(User $user): int { - return sizeof($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0])); + return sizeof($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0, "is_message_video" => 0])); } public function find(string $query = "", array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream { $query = "%$query%"; - $result = $this->videos->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("deleted", 0)->where("unlisted", 0); + $result = $this->videos->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("deleted", 0)->where("unlisted", 0)->where("is_message_video", 0); $order_str = 'id'; switch ($order['type']) { @@ -101,7 +101,7 @@ public function find(string $query = "", array $params = [], array $order = ['ty public function getLastVideo(User $user) { - $video = $this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0])->order("id DESC")->fetch(); + $video = $this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0, "is_message_video" => 0])->order("id DESC")->fetch(); return new Video($video); } diff --git a/Web/Presenters/MessengerPresenter.php b/Web/Presenters/MessengerPresenter.php index 0de178c0b..6017c3a74 100644 --- a/Web/Presenters/MessengerPresenter.php +++ b/Web/Presenters/MessengerPresenter.php @@ -143,7 +143,9 @@ public function renderApiGetMessages(int $sel, int $lastMsg): void $messages = []; $correspondence = new Correspondence($this->user->identity, $correspondent); foreach ($correspondence->getMessages(1, $lastMsg === 0 ? null : $lastMsg, null, 0) as $message) { - $messages[] = $message->simplify(); + $simple = $message->simplify(); + $this->enrichAttachmentsWithHTML($message, $simple); + $messages[] = $simple; } header("Content-Type: application/json"); @@ -166,13 +168,62 @@ public function renderApiWriteMessage(int $sel): void exit(); } + $attachments = []; + if (!empty($this->postParam("attachments"))) { + $attachments_array = array_slice(explode(",", $this->postParam("attachments")), 0, OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["maxAttachments"]); + if (sizeof($attachments_array) > 0) { + $attachments = parseAttachments($attachments_array, ['photo', 'video', 'audio', 'note', 'doc']); + } + } + $cor = new Correspondence($this->user->identity, $sel); $msg = new Message(); $msg->setContent($this->postParam("content")); $cor->sendMessage($msg); + foreach ($attachments as $attachment) { + if (!$attachment || $attachment->isDeleted() || !$attachment->canBeViewedBy($this->user->identity)) { + continue; + } + + $msg->attach($attachment); + } + header("HTTP/1.1 202 Accepted"); header("Content-Type: application/json"); - exit(json_encode($msg->simplify())); + $simple = $msg->simplify(); + $this->enrichAttachmentsWithHTML($msg, $simple); + exit(json_encode($simple)); + } + + private function enrichAttachmentsWithHTML(Message $messageObj, array &$simplifiedArray): void + { + $children = iterator_to_array($messageObj->getChildren()); + + foreach ($simplifiedArray['attachments'] as $index => &$attachmentData) { + if (!isset($children[$index])) { + continue; + } + + $originalObj = $children[$index]; + $html = ""; + + if ($attachmentData['type'] === 'audio') { + $html = $this->getTemplatingEngine()->renderToString( + # костыль жоский + dirname(__FILE__) . '/templates/Audio/player.latte', + [ + 'audio' => $originalObj, + 'thisUser' => $this->user->identity, + 'hideButtons' => false, + 'club' => null, + ] + ); + } + + if ($html !== "") { + $attachmentData['html'] = $html; + } + } } } diff --git a/Web/Presenters/PhotosPresenter.php b/Web/Presenters/PhotosPresenter.php index 63abc53d5..b145ed539 100644 --- a/Web/Presenters/PhotosPresenter.php +++ b/Web/Presenters/PhotosPresenter.php @@ -277,9 +277,11 @@ public function renderUploadPhoto(): void $this->willExecuteWriteAction(true); $upload_context = $this->queryParam("upload_context"); + $isMessageUpload = $upload_context === "messages"; + $album = null; if (is_null($this->queryParam("album"))) { - if ((int) $upload_context == $this->user->id) { + if (!$isMessageUpload && (int) $upload_context == $this->user->id) { $album = $this->albums->getUserWallAlbum($this->user->identity); } } else { @@ -339,6 +341,9 @@ public function renderUploadPhoto(): void $photo->setDescription(""); $photo->setFile($_FILES["photo_" . $i]); $photo->setCreated(time()); + if ($isMessageUpload) { + $photo->setIs_message_photo(1); + } $photo->save(); $photos[] = [ @@ -350,11 +355,10 @@ public function renderUploadPhoto(): void "pretty_id" => $photo->getPrettyId(), ]; } catch (ISE $ex) { - $name = $album->getName(); - $this->flashFail("err", "Неизвестная ошибка", "Не удалось сохранить фотографию в $name.", 500, true); + $this->flashFail("err", "Неизвестная ошибка", "Не удалось сохранить фотографию" . ($album ? " в " . $album->getName() : "") . ".", 500, true); } - if ($album != null) { + if (!$isMessageUpload && $album != null) { $album->addPhoto($photo); $album->setEdited(time()); $album->save(); diff --git a/Web/Presenters/VideosPresenter.php b/Web/Presenters/VideosPresenter.php index 8bad65c6f..581be392a 100644 --- a/Web/Presenters/VideosPresenter.php +++ b/Web/Presenters/VideosPresenter.php @@ -56,7 +56,7 @@ public function renderView(int $owner, int $vId): void if (!$video || $video->isDeleted()) { $this->notFound(); } - if (!$user->getPrivacyPermission('videos.read', $this->user->identity ?? null)) { + if (!$video->canBeViewedBy($this->user->identity)) { $this->flashFail("err", tr("forbidden"), tr("forbidden_comment")); } @@ -103,6 +103,10 @@ public function renderUpload(): void $video->setUnlisted(true); } + if ($this->queryParam("upload_context") === "messages") { + $video->setIs_message_video(1); + } + $video->save(); if ($is_ajax) { diff --git a/Web/Presenters/templates/Messenger/App.latte b/Web/Presenters/templates/Messenger/App.latte index 9cac5ff5f..21a3d14ad 100644 --- a/Web/Presenters/templates/Messenger/App.latte +++ b/Web/Presenters/templates/Messenger/App.latte @@ -29,10 +29,90 @@
+
+
+ +
+ +
+ + +
+ +
+
+
+ + +
+
+
+
+
+
+
+
+
+
+ +
+ {_note} + + + +
+
+
+
+
+
+ + + + + + +
+
+
+ +
+ + +
+
+ +
+ + + +
+ +
+
+ +
+ + + + +
+ +
+
+
+
+
+
@@ -42,15 +122,63 @@ +
{if $correspondent->getId() === $thisUser->getId() || $correspondent->getPrivacyPermission('messages.write', $thisUser)} {$thisUser->getCanonicalName()}
- - +
{$correspondent->getCanonicalName()} {else} @@ -74,6 +202,12 @@ }; this.loadHistory = _ => { window.Msg._loadHistory(); + document.body.querySelectorAll(".bsdn").forEach(el => { + if(!el.querySelector(".bdsn-hydrated")) { + bsdnInitElement(el); + } + } + ); }; this.onMessagesScroll = (model, e) => { @@ -238,6 +372,23 @@ msgData.set("content", content); msgData.set("hash", {$csrfToken}); + const writeBox = document.querySelector('.messenger-app--input #write'); + let attachmentElements = writeBox ? writeBox.querySelectorAll("[data-att-id]") : document.querySelectorAll("[data-att-id]"); + let attachmentIds = []; + if(attachmentElements && attachmentElements.length > 0) { + attachmentElements.forEach(el => { + let type = el.getAttribute("data-att-type"); + let id = el.getAttribute("data-att-id"); + if(type && id) { + attachmentIds.push(type + id); + } + }); + } + + if(attachmentIds.length > 0) { + msgData.set("attachments", attachmentIds.join(",")); + } + let that = this; let xhr = new XMLHttpRequest(); xhr.open("POST", "/im/api/messages" + {$correspondent->getId()} + "/create.json", true); @@ -266,6 +417,26 @@ console.debug("Message sent, updating view."); that._patchMessage(tempId, JSON.parse(xhr.responseText)); + + document.body.querySelectorAll(".bsdn").forEach(el => { + if(!el.querySelector(".bdsn-hydrated")) { + bsdnInitElement(el); + } + } + ); + + const writeBox = document.querySelector('#write'); + if(writeBox) { + writeBox.querySelector('.post-horizontal').innerHTML = ''; + writeBox.querySelector('.post-vertical').innerHTML = ''; + } + + const previewBox = document.querySelector('#messenger-attachment-preview'); + if(previewBox) { + previewBox.querySelector('.post-horizontal').innerHTML = ''; + previewBox.querySelector('.post-vertical').innerHTML = ''; + previewBox.style.display = 'none'; + } }); xhr.send(msgData); console.debug("Message sent, awaiting response."); @@ -273,5 +444,130 @@ } window.Msg = new Messenger([]); + + document.querySelector(".messenger-app--messages").addEventListener("click", (e) => { + if(e.target.closest(".photoMessengerOpen")) { + e.preventDefault(); + e.stopPropagation(); + const photoLink = e.target.closest(".photoMessengerOpen"); + const photoId = photoLink.getAttribute("data-photo-id"); + const photoImg = photoLink.querySelector("img"); + if(photoImg && photoId) { + OpenMiniature(e, photoImg.src, null, photoId, null); + } + } + + if(e.target.closest(".videoMessengerOpen")) { + e.preventDefault(); + e.stopPropagation(); + const videoLink = e.target.closest(".videoMessengerOpen"); + const videoId = videoLink.getAttribute("data-video-id"); + if(videoId && videoId.indexOf("_") !== -1) { + const parts = videoId.split("_"); + OpenVideo(parts); + } + } + }); + + (function() { + function syncItemToPreview(item) { + if(!item) return; + + const type = item.getAttribute('data-type') || item.getAttribute('data-att-type'); + const id = item.getAttribute('data-id') || item.getAttribute('data-att-id') || item.getAttribute('data-prettiest-id') || item.getAttribute('data-pretty-id'); + + if(type && id) { + item.setAttribute('data-att-type', type); + item.setAttribute('data-att-id', id); + + const previewBox = document.querySelector('#messenger-attachment-preview'); + if(previewBox) { + const isVertical = type === 'doc' || type === 'note' || type === 'audio'; + const container = isVertical ? + previewBox.querySelector('.post-vertical') : + previewBox.querySelector('.post-horizontal'); + if(container && !container.querySelector(`[data-att-type="${ type }"][data-att-id="${ id }"]`)) { + container.appendChild(item.cloneNode(true)); + previewBox.style.display = 'block'; + } + } + } + } + + function normalizeUploadItem(el) { + if(!el) return; + const items = el.querySelectorAll('.upload-item, .vertical-attachment'); + items.forEach(a => { + syncItemToPreview(a); + }); + } + + const write = document.querySelector('#write'); + if(write) normalizeUploadItem(write); + const observer = new MutationObserver(mutations => { + mutations.forEach(m => { + if(m.addedNodes && m.addedNodes.length) { + m.addedNodes.forEach(node => { + if(node.nodeType === 1) { + if(node.matches && (node.matches('.upload-item') || node.matches('.vertical-attachment'))) { + syncItemToPreview(node); + } else { + normalizeUploadItem(node); + } + } + }); + } + + if(m.removedNodes && m.removedNodes.length) { + const previewBox = document.querySelector('#messenger-attachment-preview'); + if (!previewBox) return; + + m.removedNodes.forEach(node => { + if(node.nodeType === 1 && node.matches && (node.matches('.upload-item') || node.matches('.vertical-attachment'))) { + const type = node.getAttribute('data-att-type') || node.getAttribute('data-type'); + const id = node.getAttribute('data-att-id') || node.getAttribute('data-id'); + + if(type && id) { + const itemToRemove = previewBox.querySelector(`[data-att-type="${ type }"][data-att-id="${ id }"], [data-type="${ type }"][data-id="${ id }"]`); + if(itemToRemove) { + itemToRemove.remove(); + } + } + } + }); + + if(previewBox.querySelectorAll('.upload-item, .vertical-attachment').length === 0) { + previewBox.style.display = 'none'; + } + } + }); + }); + if(write) observer.observe(write, { childList: true, subtree: true }); + + const previewBox = document.querySelector('#messenger-attachment-preview'); + if(previewBox) { + previewBox.addEventListener('click', function(e) { + const target = e.target; + const deleteBtn = target.closest('.upload-delete') || target.closest('#small_remove_button') || target.closest('.vertical-attachment-remove'); + + if(deleteBtn) { + e.preventDefault(); + e.stopPropagation(); + + const item = deleteBtn.closest('.upload-item, .vertical-attachment'); + if(item) { + const type = item.getAttribute('data-att-type') || item.getAttribute('data-type'); + const id = item.getAttribute('data-att-id') || item.getAttribute('data-id'); + + if(type && id && write) { + const sourceItem = write.querySelector(`[data-att-type="${ type }"][data-att-id="${ id }"], [data-type="${ type }"][data-id="${ id }"]`); + if(sourceItem) + sourceItem.remove(); + } + } + } + }); + } + })(); {/block} diff --git a/Web/static/css/main.css b/Web/static/css/main.css index d8d455b05..62b0fbc53 100644 --- a/Web/static/css/main.css +++ b/Web/static/css/main.css @@ -1323,6 +1323,11 @@ table.User { display: block; } +.messenger-app--messages---message ._content .audioEmbed .title { + display: inline; + width: auto; +} + .messenger-app--messages---message ._content span { width: 100%; height: fit-content; @@ -1334,7 +1339,7 @@ table.User { } .messenger-app--messages---message ._content .attachments>.msg-attach-j * { - max-width: 86%; + max-width: 100%; } .messenger-app--messages---message ._content .attachments:not(:empty) { diff --git a/Web/static/js/al_wall.js b/Web/static/js/al_wall.js index 22c0465bb..c2f72b449 100644 --- a/Web/static/js/al_wall.js +++ b/Web/static/js/al_wall.js @@ -1224,7 +1224,9 @@ async function __uploadToTextarea(file, textareaNode) { const rand = random_int(0, 1000) textareaNode.find('.post-horizontal').append(``) - const res = await fetch(`/photos/upload?upload_context=${textareaNode.nodes[0].dataset.id}`, { + const writeEl = textareaNode.nodes[0] + const photoUploadContext = writeEl.dataset.context === 'messages' ? 'messages' : writeEl.dataset.id + const res = await fetch(`/photos/upload?upload_context=${photoUploadContext}`, { method: 'POST', body: form_data }) @@ -1467,7 +1469,7 @@ u(document).on("click", "#__photoAttachment", async (e) => { u(".ovk-diag-body #__pickerQuickUpload").on('change', (ev) => { for(file of ev.target.files) { try { - __uploadToTextarea(file, form) + __uploadToTextarea(file, form.closest('#write')) } catch(e) { makeError(e.message) return @@ -1488,13 +1490,15 @@ u(document).on("click", "#__photoAttachment", async (e) => { u(document).on('click', '#__videoAttachment', async (e) => { const per_page = 10 - const form = u(e.target).closest('form') + const form = u(e.target).closest('form') + const isMessageContext = form.nodes[0]?.closest('#write')?.dataset?.context === 'messages' + const videoUploadUrl = isMessageContext ? '/videos/upload?upload_context=messages' : '/videos/upload' const msg = new CMessageBox({ title: tr('selecting_video'), body: `
- +
@@ -1776,6 +1780,8 @@ u(document).on('click', '#__notesAttachment', async (e) => { }) function showFastVideoUpload(node) { + const isMessageContext = node.nodes[0]?.closest('#write')?.dataset?.context === 'messages' + const uploadUrl = isMessageContext ? '/videos/upload?upload_context=messages' : '/videos/upload' let current_tab = 'file' const msg = new CMessageBox({ title: tr('upload_video'), @@ -1829,7 +1835,7 @@ function showFastVideoUpload(node) { form_data.append("hash", u("meta[name=csrf]").attr("value")) window.messagebox_stack[1].getNode().find('.ovk-diag-action button').nodes[1].classList.add('lagged') - const fetcher = await fetch(`/videos/upload`, { + const fetcher = await fetch(uploadUrl, { method: 'POST', body: form_data }) @@ -1853,7 +1859,7 @@ function showFastVideoUpload(node) { form_data.append("hash", u("meta[name=csrf]").attr("value")) window.messagebox_stack[1].getNode().find('.ovk-diag-action button').nodes[1].classList.add('lagged') - const fetcher_yt = await fetch(`/videos/upload`, { + const fetcher_yt = await fetch(uploadUrl, { method: 'POST', body: form_data }) diff --git a/install/sqls/00061-message-attachments-privacy.sql b/install/sqls/00061-message-attachments-privacy.sql new file mode 100644 index 000000000..cd7651588 --- /dev/null +++ b/install/sqls/00061-message-attachments-privacy.sql @@ -0,0 +1,2 @@ +ALTER TABLE `photos` ADD COLUMN `is_message_photo` TINYINT(1) NOT NULL DEFAULT 0; +ALTER TABLE `videos` ADD COLUMN `is_message_video` TINYINT(1) NOT NULL DEFAULT 0;