diff --git a/ServiceAPI/Wall.php b/ServiceAPI/Wall.php
index 5677f7ba..787a998e 100644
--- a/ServiceAPI/Wall.php
+++ b/ServiceAPI/Wall.php
@@ -2,7 +2,7 @@
namespace openvk\ServiceAPI;
use openvk\Web\Models\Entities\Post;
use openvk\Web\Models\Entities\User;
-use openvk\Web\Models\Repositories\{Posts, Notes};
+use openvk\Web\Models\Repositories\{Posts, Notes, Videos};
class Wall implements Handler
{
@@ -15,6 +15,7 @@ class Wall implements Handler
$this->user = $user;
$this->posts = new Posts;
$this->notes = new Notes;
+ $this->videos = new Videos;
}
function getPost(int $id, callable $resolve, callable $reject): void
@@ -95,4 +96,45 @@ class Wall implements Handler
$resolve($arr);
}
+
+ function getVideos(int $page = 1, callable $resolve, callable $reject)
+ {
+ $videos = $this->videos->getByUser($this->user, $page, 8);
+ $count = $this->videos->getUserVideosCount($this->user);
+
+ $arr = [
+ "count" => $count,
+ "items" => [],
+ ];
+
+ foreach($videos as $video) {
+ $res = json_decode(json_encode($video->toVkApiStruct()), true);
+ $res["video"]["author_name"] = $video->getOwner()->getCanonicalName();
+
+ $arr["items"][] = $res;
+ }
+
+ $resolve($arr);
+ }
+
+ function searchVideos(int $page = 1, string $query, callable $resolve, callable $reject)
+ {
+ $dbc = $this->videos->find($query);
+ $videos = $dbc->page($page, 8);
+ $count = $dbc->size();
+
+ $arr = [
+ "count" => $count,
+ "items" => [],
+ ];
+
+ foreach($videos as $video) {
+ $res = json_decode(json_encode($video->toVkApiStruct()), true);
+ $res["video"]["author_name"] = $video->getOwner()->getCanonicalName();
+
+ $arr["items"][] = $res;
+ }
+
+ $resolve($arr);
+ }
}
diff --git a/VKAPI/Handlers/Wall.php b/VKAPI/Handlers/Wall.php
index d52dfce1..6b78a0b0 100644
--- a/VKAPI/Handlers/Wall.php
+++ b/VKAPI/Handlers/Wall.php
@@ -463,28 +463,25 @@ final class Wall extends VKAPIRequestHandler
if($attachmentType == "photo") {
$attacc = (new PhotosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
if(!$attacc || $attacc->isDeleted())
- $this->fail(100, "Photo does not exists");
- if($attacc->getOwner()->getId() != $this->getUser()->getId())
- $this->fail(43, "You do not have access to this photo");
+ $this->fail(100, "Invalid photo");
+ if(!$attacc->getOwner()->getPrivacyPermission('photos.read', $this->getUser()))
+ $this->fail(43, "Access to photo denied");
$post->attach($attacc);
} elseif($attachmentType == "video") {
$attacc = (new VideosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
if(!$attacc || $attacc->isDeleted())
$this->fail(100, "Video does not exists");
- if($attacc->getOwner()->getId() != $this->getUser()->getId())
- $this->fail(43, "You do not have access to this video");
+ if(!$attacc->getOwner()->getPrivacyPermission('videos.read', $this->getUser()))
+ $this->fail(43, "Access to video denied");
$post->attach($attacc);
} elseif($attachmentType == "note") {
$attacc = (new NotesRepo)->getNoteById($attachmentOwner, $attachmentId);
if(!$attacc || $attacc->isDeleted())
$this->fail(100, "Note does not exist");
- if($attacc->getOwner()->getId() != $this->getUser()->getId())
- $this->fail(43, "You do not have access to this note");
-
- if($attacc->getOwner()->getPrivacySetting("notes.read") < 1)
- $this->fail(11, "You can't attach note to post, because your notes list is closed. Change it in privacy settings in web-version.");
+ if(!$attacc->getOwner()->getPrivacyPermission('notes.read', $this->getUser()))
+ $this->fail(11, "Access to note denied");
$post->attach($attacc);
}
@@ -678,7 +675,7 @@ final class Wall extends VKAPIRequestHandler
return $response;
}
- function createComment(int $owner_id, int $post_id, string $message, int $from_group = 0, string $attachments = "") {
+ function createComment(int $owner_id, int $post_id, string $message = "", int $from_group = 0, string $attachments = "") {
$this->requireUser();
$this->willExecuteWriteAction();
@@ -736,16 +733,16 @@ final class Wall extends VKAPIRequestHandler
$attacc = (new PhotosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
if(!$attacc || $attacc->isDeleted())
$this->fail(100, "Photo does not exists");
- if($attacc->getOwner()->getId() != $this->getUser()->getId())
- $this->fail(43, "You do not have access to this photo");
+ if(!$attacc->getOwner()->getPrivacyPermission('photos.read', $this->getUser()))
+ $this->fail(11, "Access to photo denied");
$comment->attach($attacc);
} elseif($attachmentType == "video") {
$attacc = (new VideosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
if(!$attacc || $attacc->isDeleted())
$this->fail(100, "Video does not exists");
- if($attacc->getOwner()->getId() != $this->getUser()->getId())
- $this->fail(43, "You do not have access to this video");
+ if(!$attacc->getOwner()->getPrivacyPermission('videos.read', $this->getUser()))
+ $this->fail(11, "Access to video denied");
$comment->attach($attacc);
}
diff --git a/Web/Presenters/CommentPresenter.php b/Web/Presenters/CommentPresenter.php
index 29c54c78..b68c7d11 100644
--- a/Web/Presenters/CommentPresenter.php
+++ b/Web/Presenters/CommentPresenter.php
@@ -2,7 +2,7 @@
namespace openvk\Web\Presenters;
use openvk\Web\Models\Entities\{Comment, Notifications\MentionNotification, Photo, Video, User, Topic, Post};
use openvk\Web\Models\Entities\Notifications\CommentNotification;
-use openvk\Web\Models\Repositories\{Comments, Clubs};
+use openvk\Web\Models\Repositories\{Comments, Clubs, Videos};
final class CommentPresenter extends OpenVKPresenter
{
@@ -73,7 +73,6 @@ final class CommentPresenter extends OpenVKPresenter
# TODO move to trait
try {
$photo = NULL;
- $video = NULL;
if($_FILES["_pic_attachment"]["error"] === UPLOAD_ERR_OK) {
$album = NULL;
if($wall > 0 && $wall === $this->user->id)
@@ -81,13 +80,28 @@ final class CommentPresenter extends OpenVKPresenter
$photo = Photo::fastMake($this->user->id, $this->postParam("text"), $_FILES["_pic_attachment"], $album);
}
-
- if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK) {
- $video = Video::fastMake($this->user->id, $_FILES["_vid_attachment"]["name"], $this->postParam("text"), $_FILES["_vid_attachment"]);
- }
} catch(ISE $ex) {
$this->flashFail("err", tr("error_when_publishing_comment"), tr("error_comment_file_too_big"));
}
+
+ $videos = [];
+
+ if(!empty($this->postParam("videos"))) {
+ $un = rtrim($this->postParam("videos"), ",");
+ $arr = explode(",", $un);
+
+ if(sizeof($arr) < 11) {
+ foreach($arr as $dat) {
+ $ids = explode("_", $dat);
+ $video = (new Videos)->getByOwnerAndVID((int)$ids[0], (int)$ids[1]);
+
+ if(!$video || $video->isDeleted())
+ continue;
+
+ $videos[] = $video;
+ }
+ }
+ }
if(empty($this->postParam("text")) && !$photo && !$video)
$this->flashFail("err", tr("error_when_publishing_comment"), tr("error_comment_empty"));
@@ -108,8 +122,9 @@ final class CommentPresenter extends OpenVKPresenter
if(!is_null($photo))
$comment->attach($photo);
- if(!is_null($video))
- $comment->attach($video);
+ if(sizeof($videos) > 0)
+ foreach($videos as $vid)
+ $comment->attach($vid);
if($entity->getOwner()->getId() !== $this->user->identity->getId())
if(($owner = $entity->getOwner()) instanceof User)
diff --git a/Web/Presenters/WallPresenter.php b/Web/Presenters/WallPresenter.php
index 32ac421e..ef9e4689 100644
--- a/Web/Presenters/WallPresenter.php
+++ b/Web/Presenters/WallPresenter.php
@@ -3,7 +3,7 @@ namespace openvk\Web\Presenters;
use openvk\Web\Models\Exceptions\TooMuchOptionsException;
use openvk\Web\Models\Entities\{Poll, Post, Photo, Video, Club, User};
use openvk\Web\Models\Entities\Notifications\{MentionNotification, RepostNotification, WallPostNotification};
-use openvk\Web\Models\Repositories\{Posts, Users, Clubs, Albums, Notes, Comments};
+use openvk\Web\Models\Repositories\{Posts, Users, Clubs, Albums, Notes, Videos, Comments};
use Chandler\Database\DatabaseConnection;
use Nette\InvalidStateException as ISE;
use Bhaktaraz\RSSGenerator\Item;
@@ -231,10 +231,7 @@ final class WallPresenter extends OpenVKPresenter
if(!$canPost)
$this->flashFail("err", tr("not_enough_permissions"), tr("not_enough_permissions_comment"));
-
- if($_FILES["_vid_attachment"] && OPENVK_ROOT_CONF['openvk']['preferences']['videos']['disableUploading'])
- $this->flashFail("err", tr("error"), tr("video_uploads_disabled"));
-
+
$anon = OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["enable"];
if($wallOwner instanceof Club && $this->postParam("as_group") === "on" && $this->postParam("force_sign") !== "on" && $anon) {
$manager = $wallOwner->getManager($this->user->identity);
@@ -263,8 +260,8 @@ final class WallPresenter extends OpenVKPresenter
$photo = Photo::fastMake($this->user->id, $this->postParam("text"), $_FILES["_pic_attachment"], $album, $anon);
}
- if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK)
- $video = Video::fastMake($this->user->id, $_FILES["_vid_attachment"]["name"], $this->postParam("text"), $_FILES["_vid_attachment"], $anon);
+ /*if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK)
+ $video = Video::fastMake($this->user->id, $_FILES["_vid_attachment"]["name"], $this->postParam("text"), $_FILES["_vid_attachment"], $anon);*/
} catch(\DomainException $ex) {
$this->flashFail("err", tr("failed_to_publish_post"), tr("media_file_corrupted"));
} catch(ISE $ex) {
@@ -295,8 +292,27 @@ final class WallPresenter extends OpenVKPresenter
$this->flashFail("err", " ");
}
}
+
+ $videos = [];
+
+ if(!empty($this->postParam("videos"))) {
+ $un = rtrim($this->postParam("videos"), ",");
+ $arr = explode(",", $un);
+
+ if(sizeof($arr) < 11) {
+ foreach($arr as $dat) {
+ $ids = explode("_", $dat);
+ $video = (new Videos)->getByOwnerAndVID((int)$ids[0], (int)$ids[1]);
+
+ if(!$video || $video->isDeleted())
+ continue;
+
+ $videos[] = $video;
+ }
+ }
+ }
- if(empty($this->postParam("text")) && !$photo && !$video && !$poll && !$note)
+ if(empty($this->postParam("text")) && !$photo && sizeof($videos) < 1 && !$poll && !$note)
$this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_empty_or_too_big"));
try {
@@ -316,8 +332,9 @@ final class WallPresenter extends OpenVKPresenter
if(!is_null($photo))
$post->attach($photo);
- if(!is_null($video))
- $post->attach($video);
+ if(sizeof($videos) > 0)
+ foreach($videos as $vid)
+ $post->attach($vid);
if(!is_null($poll))
$post->attach($poll);
diff --git a/Web/Presenters/templates/components/textArea.xml b/Web/Presenters/templates/components/textArea.xml
index f76649d6..939e5ad5 100644
--- a/Web/Presenters/templates/components/textArea.xml
+++ b/Web/Presenters/templates/components/textArea.xml
@@ -17,6 +17,8 @@
+
+
{var $anonEnabled = OPENVK_ROOT_CONF['openvk']['preferences']['wall']['anonymousPosting']['enable']}
{if !is_null($thisUser) && !is_null($club ?? NULL) && $owner < 0}
@@ -55,7 +57,7 @@
-
+
@@ -75,7 +77,7 @@
{_photo}
-
+
{_video}
@@ -105,6 +107,8 @@
setupWallPostInputHandlers({$textAreaId});
});
+
+ u("#post-buttons{$textAreaId} input[name='videos']")["nodes"].at(0).value = ""
{if $graffiti}
diff --git a/Web/static/css/main.css b/Web/static/css/main.css
index 46ad74b0..caa49283 100644
--- a/Web/static/css/main.css
+++ b/Web/static/css/main.css
@@ -1466,6 +1466,12 @@ body.scrolled .toTop:hover {
display: none;
}
+.post-has-videos {
+ margin-top: 11px;
+ margin-left: 3px;
+ color: #3c3c3c;
+}
+
.post-upload::before, .post-has-poll::before, .post-has-note::before {
content: " ";
width: 8px;
@@ -1477,6 +1483,28 @@ body.scrolled .toTop:hover {
margin-left: 2px;
}
+.post-has-video {
+ padding-bottom: 4px;
+ cursor: pointer;
+}
+
+.post-has-video:hover span {
+ text-decoration: underline;
+}
+
+.post-has-video::before {
+ content: " ";
+ width: 14px;
+ height: 15px;
+ display: inline-block;
+ vertical-align: bottom;
+ background-image: url("/assets/packages/static/openvk/img/video.png");
+ background-repeat: no-repeat;
+ margin: 3px;
+ margin-left: 2px;
+ margin-bottom: -1px;
+}
+
.post-opts {
margin-top: 10px;
}
@@ -2702,6 +2730,12 @@ body.article .floating_sidebar, body.article .page_content {
font-size: 12px;
}
+.topGrayBlock {
+ background: #F0F0F0;
+ height: 37px;
+ border-bottom: 1px solid #C7C7C7;
+}
+
.edited {
color: #9b9b9b;
}
diff --git a/Web/static/img/video.png b/Web/static/img/video.png
new file mode 100644
index 00000000..5c115f1c
Binary files /dev/null and b/Web/static/img/video.png differ
diff --git a/Web/static/js/al_wall.js b/Web/static/js/al_wall.js
index 4c8bb933..ef3d5dba 100644
--- a/Web/static/js/al_wall.js
+++ b/Web/static/js/al_wall.js
@@ -264,6 +264,160 @@ async function showArticle(note_id) {
u("body").addClass("article");
}
+$(document).on("click", "#videoAttachment", async (e) => {
+ e.preventDefault()
+
+ let body = `
+
+
+
+ `
+
+ let form = e.currentTarget.closest("form")
+
+ MessageBox(tr("selecting_video"), body, [tr("close")], [Function.noop]);
+
+ // styles for messageboxx
+ document.querySelector(".ovk-diag-body").style.padding = "0"
+ document.querySelector(".ovk-diag-cont").style.width = "580px"
+ document.querySelector(".ovk-diag-body").style.height = "335px"
+
+ async function insertVideos(page, query = "") {
+ document.querySelector(".videosInsert").insertAdjacentHTML("beforeend", ``)
+
+ let vidoses
+ let noVideosText = tr("no_videos")
+ if(query == "") {
+ vidoses = await API.Wall.getVideos(page)
+ } else {
+ vidoses = await API.Wall.searchVideos(page, query)
+ noVideosText = tr("no_videos_results")
+ }
+
+ if(vidoses.count < 1) {
+ document.querySelector(".videosInsert").innerHTML = `${noVideosText}`
+ }
+
+ let pagesCount = Math.ceil(Number(vidoses.count) / 8)
+ u("#loader").remove()
+ let insert = document.querySelector(".videosInsert")
+
+ for(const vid of vidoses.items) {
+ let isAttached = (form.querySelector("input[name='videos']").value.includes(`${vid.video.owner_id}_${vid.video.id},`))
+
+ insert.insertAdjacentHTML("beforeend", `
+
+ `)
+ }
+
+ if(page < pagesCount) {
+ document.querySelector(".videosInsert").insertAdjacentHTML("beforeend", `
+
+ more...
+
`)
+ }
+ }
+
+ $(".videosInsert").on("click", "#showMoreVideos", (e) => {
+ u(e.currentTarget).remove()
+ insertVideos(Number(e.currentTarget.dataset.page), document.querySelector(".topGrayBlock #vquery").value)
+ })
+
+ $(".topGrayBlock #vquery").on("change", async (e) => {
+ await new Promise(r => setTimeout(r, 1000));
+
+ if(e.currentTarget.value === document.querySelector(".topGrayBlock #vquery").value) {
+ document.querySelector(".videosInsert").innerHTML = ""
+ insertVideos(1, e.currentTarget.value)
+ return;
+ } else {
+ console.info("skipping")
+ }
+ })
+
+ insertVideos(1)
+
+ function insertAttachment(id) {
+ let videos = form.querySelector("input[name='videos']")
+
+ if(!videos.value.includes(id + ",")) {
+ if(videos.value.split(",").length > 10) {
+ NewNotification(tr("error"), tr("max_attached_videos"))
+ return false
+ }
+
+ form.querySelector("input[name='videos']").value += (id + ",")
+
+ console.info(id + " attached")
+ return true
+ } else {
+ form.querySelector("input[name='videos']").value = form.querySelector("input[name='videos']").value.replace(id + ",", "")
+
+ console.info(id + " detached")
+ return false
+ }
+ }
+
+ $(".videosInsert").on("click", "#attachvid", (ev) => {
+ // откреплено от псто
+ if(!insertAttachment(ev.currentTarget.dataset.attachmentdata)) {
+ u(`.post-has-videos .post-has-video[data-id='${ev.currentTarget.dataset.attachmentdata}']`).remove()
+ ev.currentTarget.innerHTML = tr("attach")
+ } else {
+ ev.currentTarget.innerHTML = tr("detach")
+
+ form.querySelector(".post-has-videos").insertAdjacentHTML("beforeend", `
+
+ ${tr("video")} "${ovk_proc_strtr(escapeHtml(ev.currentTarget.dataset.name), 20)}"
+
+ `)
+
+ u(`#unattachVideo[data-id='${ev.currentTarget.dataset.attachmentdata}']`).on("click", (e) => {
+ let id = ev.currentTarget.dataset.attachmentdata
+ form.querySelector("input[name='videos']").value = form.querySelector("input[name='videos']").value.replace(id + ",", "")
+
+ console.info(id + " detached")
+
+ u(e.currentTarget).remove()
+ })
+ }
+ })
+})
+
$(document).on("click", "#editPost", (e) => {
let post = e.currentTarget.closest("table")
let content = post.querySelector(".text")
diff --git a/Web/static/js/messagebox.js b/Web/static/js/messagebox.js
index 45791fd3..368311dd 100644
--- a/Web/static/js/messagebox.js
+++ b/Web/static/js/messagebox.js
@@ -3,6 +3,7 @@ Function.noop = () => {};
function MessageBox(title, body, buttons, callbacks) {
if(u(".ovk-diag-cont").length > 0) return false;
+ document.querySelector("html").style.overflowY = "hidden"
let dialog = u(
`
@@ -21,6 +22,7 @@ function MessageBox(title, body, buttons, callbacks) {
let __closeDialog = () => {
u("body").removeClass("dimmed");
u(".ovk-diag-cont").remove();
+ document.querySelector("html").style.overflowY = "scroll"
};
Reflect.apply(callbacks[callback], {
diff --git a/locales/en.strings b/locales/en.strings
index f09ee65e..22cee453 100644
--- a/locales/en.strings
+++ b/locales/en.strings
@@ -206,6 +206,7 @@
"nsfw_warning" = "This post may have NSFW-content";
"report" = "Report";
"attach" = "Attach";
+"detach" = "Detach";
"attach_photo" = "Attach photo";
"attach_video" = "Attach video";
"draw_graffiti" = "Draw graffiti";
@@ -692,6 +693,13 @@
"videos_other" = "$1 videos";
"view_video" = "View";
+
+"selecting_video" = "Selecting videos";
+"upload_new_video" = "Upload new video";
+"max_attached_videos" = "Max is 10 videos";
+"no_videos" = "You don't have uploaded videos.";
+"no_videos_results" = "No results.";
+
"change_video" = "Change video";
"unknown_video" = "This video is not supported in your version of OpenVK.";
diff --git a/locales/ru.strings b/locales/ru.strings
index 787f1648..2dfadb8f 100644
--- a/locales/ru.strings
+++ b/locales/ru.strings
@@ -186,6 +186,7 @@
"nsfw_warning" = "Данный пост может содержать 18+ контент";
"report" = "Пожаловаться";
"attach" = "Прикрепить";
+"detach" = "Открепить";
"attach_photo" = "Прикрепить фото";
"attach_video" = "Прикрепить видео";
"draw_graffiti" = "Нарисовать граффити";
@@ -652,6 +653,12 @@
"change_video" = "Изменить видеозапись";
"unknown_video" = "Эта видеозапись не поддерживается в вашей версии OpenVK.";
+"selecting_video" = "Выбор видеозаписей";
+"upload_new_video" = "Загрузить новое видео";
+"max_attached_videos" = "Максимум 10 видеозаписей";
+"no_videos" = "У вас нет видео.";
+"no_videos_results" = "Нет результатов.";
+
/* Notifications */
"feedback" = "Ответы";