diff --git a/ServiceAPI/Wall.php b/ServiceAPI/Wall.php index 628ceb22..16358e93 100644 --- a/ServiceAPI/Wall.php +++ b/ServiceAPI/Wall.php @@ -2,17 +2,19 @@ namespace openvk\ServiceAPI; use openvk\Web\Models\Entities\Post; use openvk\Web\Models\Entities\User; -use openvk\Web\Models\Repositories\Posts; +use openvk\Web\Models\Repositories\{Posts, Notes}; class Wall implements Handler { protected $user; protected $posts; + protected $notes; function __construct(?User $user) { $this->user = $user; $this->posts = new Posts; + $this->notes = new Notes; } function getPost(int $id, callable $resolve, callable $reject): void @@ -71,4 +73,25 @@ class Wall implements Handler $resolve($post->getId()); } + + function getMyNotes(callable $resolve, callable $reject) + { + $myNotes = $this->notes->getUserNotes($this->user, 1, $this->notes->getUserNotesCount($this->user)); + + $arr = [ + "count" => sizeof($myNotes), + "closed" => $this->user->getPrivacySetting("notes.read"), + "items" => [], + ]; + + foreach($myNotes as $note) { + $arr["items"][] = [ + "id" => $note->getId(), + "name" => ovk_proc_strtr($note->getName(), 30), + #"preview" => $note->getPreview() + ]; + } + + $resolve($arr); + } } diff --git a/VKAPI/Handlers/Notes.php b/VKAPI/Handlers/Notes.php index d3dc3468..ce26baae 100644 --- a/VKAPI/Handlers/Notes.php +++ b/VKAPI/Handlers/Notes.php @@ -40,6 +40,9 @@ final class Notes extends VKAPIRequestHandler if($note->getOwner()->isDeleted()) $this->fail(403, "Owner is deleted"); + if(!$note->getOwner()->getPrivacyPermission('notes.read', $this->getUser())) + $this->fail(43, "No access"); + if(empty($message) && empty($attachments)) $this->fail(100, "Required parameter 'message' missing."); @@ -183,6 +186,9 @@ final class Notes extends VKAPIRequestHandler if(!$user || $user->isDeleted()) $this->fail(15, "Invalid user"); + if(!$user->getPrivacyPermission('notes.read', $this->getUser())) + $this->fail(43, "Access denied: this user chose to hide his notes"); + if(empty($note_ids)) { $notes = array_slice(iterator_to_array((new NotesRepo)->getUserNotes($user, 1, $count + $offset, $sort == 0 ? "ASC" : "DESC")), $offset); $nodez = (object) [ @@ -225,10 +231,13 @@ final class Notes extends VKAPIRequestHandler if($note->isDeleted()) $this->fail(189, "Note is deleted"); - + if(!$note->getOwner() || $note->getOwner()->isDeleted()) $this->fail(177, "Owner does not exists"); + if(!$note->getOwner()->getPrivacyPermission('notes.read', $this->getUser())) + $this->fail(40, "Access denied: this user chose to hide his notes"); + return $note->toVkApiStruct(); } @@ -246,6 +255,9 @@ final class Notes extends VKAPIRequestHandler if(!$note->getOwner()) $this->fail(177, "Owner does not exists"); + + if(!$note->getOwner()->getPrivacyPermission('notes.read', $this->getUser())) + $this->fail(14, "No access"); $arr = (object) [ "count" => $note->getCommentsCount(), diff --git a/VKAPI/Handlers/Wall.php b/VKAPI/Handlers/Wall.php index 927d74ae..cc1204ae 100644 --- a/VKAPI/Handlers/Wall.php +++ b/VKAPI/Handlers/Wall.php @@ -13,6 +13,8 @@ use openvk\Web\Models\Entities\Photo; use openvk\Web\Models\Repositories\Photos as PhotosRepo; use openvk\Web\Models\Entities\Video; use openvk\Web\Models\Repositories\Videos as VideosRepo; +use openvk\Web\Models\Entities\Note; +use openvk\Web\Models\Repositories\Notes as NotesRepo; final class Wall extends VKAPIRequestHandler { @@ -54,6 +56,8 @@ final class Wall extends VKAPIRequestHandler $attachments[] = $this->getApiPoll($attachment, $this->getUser()); } else if ($attachment instanceof \openvk\Web\Models\Entities\Video) { $attachments[] = $attachment->getApiStructure(); + } else if ($attachment instanceof \openvk\Web\Models\Entities\Note) { + $attachments[] = $attachment->toVkApiStruct(); } else if ($attachment instanceof \openvk\Web\Models\Entities\Post) { $repostAttachments = []; @@ -226,6 +230,8 @@ final class Wall extends VKAPIRequestHandler $attachments[] = $this->getApiPoll($attachment, $user); } else if ($attachment instanceof \openvk\Web\Models\Entities\Video) { $attachments[] = $attachment->getApiStructure(); + } else if ($attachment instanceof \openvk\Web\Models\Entities\Note) { + $attachments[] = $attachment->toVkApiStruct(); } else if ($attachment instanceof \openvk\Web\Models\Entities\Post) { $repostAttachments = []; @@ -440,6 +446,8 @@ final class Wall extends VKAPIRequestHandler $attachmentType = "photo"; elseif(str_contains($attac, "video")) $attachmentType = "video"; + elseif(str_contains($attac, "note")) + $attachmentType = "note"; else $this->fail(205, "Unknown attachment type"); @@ -465,6 +473,17 @@ final class Wall extends VKAPIRequestHandler if($attacc->getOwner()->getId() != $this->getUser()->getId()) $this->fail(43, "You do not have access to this video"); + $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."); + $post->attach($attacc); } } @@ -542,6 +561,8 @@ final class Wall extends VKAPIRequestHandler foreach($comment->getChildren() as $attachment) { if($attachment instanceof \openvk\Web\Models\Entities\Photo) { $attachments[] = $this->getApiPhoto($attachment); + } elseif($attachment instanceof \openvk\Web\Models\Entities\Note) { + $attachments[] = $attachment->toVkApiStruct(); } } @@ -599,8 +620,8 @@ final class Wall extends VKAPIRequestHandler function getComment(int $owner_id, int $comment_id, bool $extended = false, string $fields = "sex,screen_name,photo_50,photo_100,online_info,online") { $this->requireUser(); - $comment = (new CommentsRepo)->get($comment_id); // один хуй айди всех комментов общий - + $comment = (new CommentsRepo)->get($comment_id); # один хуй айди всех комментов общий + $profiles = []; $attachments = []; diff --git a/Web/Models/Entities/Note.php b/Web/Models/Entities/Note.php index d259c2a5..37d9ac29 100644 --- a/Web/Models/Entities/Note.php +++ b/Web/Models/Entities/Note.php @@ -123,6 +123,7 @@ class Note extends Postable { $res = (object) []; + $res->type = "note"; $res->id = $this->getId(); $res->owner_id = $this->getOwner()->getId(); $res->title = $this->getName(); diff --git a/Web/Presenters/WallPresenter.php b/Web/Presenters/WallPresenter.php index 6b9ec183..727101ff 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}; +use openvk\Web\Models\Repositories\{Posts, Users, Clubs, Albums, Notes}; use Chandler\Database\DatabaseConnection; use Nette\InvalidStateException as ISE; use Bhaktaraz\RSSGenerator\Item; @@ -278,8 +278,22 @@ final class WallPresenter extends OpenVKPresenter } catch(\UnexpectedValueException $e) { $this->flashFail("err", tr("failed_to_publish_post"), "Poll format invalid"); } + + $note = NULL; + + if(!is_null($this->postParam("note")) && $this->postParam("note") != "none") { + $note = (new Notes)->get((int)$this->postParam("note")); + + if(!$note || $note->isDeleted() || $note->getOwner()->getId() != $this->user->id) { + $this->flashFail("err", tr("error"), tr("error_attaching_note")); + } + + if($note->getOwner()->getPrivacySetting("notes.read") < 1) { + $this->flashFail("err", " "); + } + } - if(empty($this->postParam("text")) && !$photo && !$video && !$poll) + if(empty($this->postParam("text")) && !$photo && !$video && !$poll && !$note) $this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_empty_or_too_big")); try { @@ -304,6 +318,9 @@ final class WallPresenter extends OpenVKPresenter if(!is_null($poll)) $post->attach($poll); + + if(!is_null($note)) + $post->attach($note); if($wall > 0 && $wall !== $this->user->identity->getId()) (new WallPostNotification($wallOwner, $post, $this->user->identity))->emit(); diff --git a/Web/Presenters/templates/Wall/Feed.xml b/Web/Presenters/templates/Wall/Feed.xml index b7f405a4..5ed1e2fb 100644 --- a/Web/Presenters/templates/Wall/Feed.xml +++ b/Web/Presenters/templates/Wall/Feed.xml @@ -16,7 +16,7 @@
- {include "../components/textArea.xml", route => "/wall" . $thisUser->getId() . "/makePost", graffiti => true, polls => true} + {include "../components/textArea.xml", route => "/wall" . $thisUser->getId() . "/makePost", graffiti => true, polls => true, notes => true}
{foreach $posts as $post} diff --git a/Web/Presenters/templates/components/attachment.xml b/Web/Presenters/templates/components/attachment.xml index 2b70b768..667c4f52 100644 --- a/Web/Presenters/templates/components/attachment.xml +++ b/Web/Presenters/templates/components/attachment.xml @@ -28,6 +28,20 @@ {elseif $attachment instanceof \openvk\Web\Models\Entities\Poll} {presenter "openvk!Poll->view", $attachment->getId()} +{elseif $attachment instanceof \openvk\Web\Models\Entities\Note} + {if !$attachment->isDeleted()} +
+ + {_note} + {ovk_proc_strtr($attachment->getName(), 66)} +
+ {else} +
+ + {_note} + {_deleted} +
+ {/if} {elseif $attachment instanceof \openvk\Web\Models\Entities\Post} {php $GLOBALS["_nesAttGloCou"] = (isset($GLOBALS["_nesAttGloCou"]) ? $GLOBALS["_nesAttGloCou"] : 0) + 1} {if $GLOBALS["_nesAttGloCou"] > 2} diff --git a/Web/Presenters/templates/components/textArea.xml b/Web/Presenters/templates/components/textArea.xml index 5e51ff76..f76649d6 100644 --- a/Web/Presenters/templates/components/textArea.xml +++ b/Web/Presenters/templates/components/textArea.xml @@ -13,6 +13,9 @@
{_poll} +
+
+
{var $anonEnabled = OPENVK_ROOT_CONF['openvk']['preferences']['wall']['anonymousPosting']['enable']} @@ -54,6 +57,7 @@ +
@@ -75,6 +79,10 @@ {_video} + + + {_note} + {_graffiti} diff --git a/Web/Presenters/templates/components/wall.xml b/Web/Presenters/templates/components/wall.xml index c2f5089a..7d205781 100644 --- a/Web/Presenters/templates/components/wall.xml +++ b/Web/Presenters/templates/components/wall.xml @@ -8,7 +8,7 @@
- {include "../components/textArea.xml", route => "/wall$owner/makePost", graffiti => true, polls => true} + {include "../components/textArea.xml", route => "/wall$owner/makePost", graffiti => true, polls => true, notes => true}
diff --git a/Web/static/css/main.css b/Web/static/css/main.css index 485aaf57..989156e2 100644 --- a/Web/static/css/main.css +++ b/Web/static/css/main.css @@ -1453,14 +1453,14 @@ body.scrolled .toTop:hover { font-weight: bold; } -.post-upload, .post-has-poll { +.post-upload, .post-has-poll, .post-has-note { margin-top: 11px; margin-left: 3px; color: #3c3c3c; display: none; } -.post-upload::before, .post-has-poll::before { +.post-upload::before, .post-has-poll::before, .post-has-note::before { content: " "; width: 8px; height: 8px; @@ -2533,3 +2533,35 @@ a.poll-retract-vote { { background: rgb(236, 235, 235); } + +.attachment_note_icon { + max-width: 9px; +} + +.attachment_note_text { + color: #605F63; + margin-left: 2px; +} + +.attachment_note { + user-select: none; +} + +#notesList +{ + overflow-y: scroll; + max-height: 130px; + margin-top: 5px; +} + +.ntSelect +{ + cursor: pointer; + padding: 6px; + +} + +.ntSelect:hover +{ + background-color: rgb(233, 232, 232); +} diff --git a/Web/static/img/note.svg b/Web/static/img/note.svg new file mode 100644 index 00000000..9583bb3b --- /dev/null +++ b/Web/static/img/note.svg @@ -0,0 +1 @@ +note \ No newline at end of file diff --git a/Web/static/js/al_wall.js b/Web/static/js/al_wall.js index 238cc104..867beb73 100644 --- a/Web/static/js/al_wall.js +++ b/Web/static/js/al_wall.js @@ -189,3 +189,64 @@ tippy(".client_app", { } }); +function addNote(textareaId, nid) +{ + if(nid > 0) { + note.value = nid + let noteObj = document.querySelector("#nd"+nid) + + let nortd = document.querySelector("#post-buttons"+textareaId+" .post-has-note"); + nortd.style.display = "block" + + nortd.innerHTML = `${tr("note")} ${escapeHtml(noteObj.dataset.name)}` + } else { + note.value = "none" + + let nortd = document.querySelector("#post-buttons"+textareaId+" .post-has-note"); + nortd.style.display = "none" + + nortd.innerHTML = "" + } + + u("body").removeClass("dimmed"); + u(".ovk-diag-cont").remove(); +} + +async function attachNote(id) +{ + let notes = await API.Wall.getMyNotes() + let body = `` + + if(notes.closed < 1) { + body = `${tr("notes_closed")}` + } else { + if(notes.items.length < 1) { + body = `${tr("no_notes")}` + } else { + body = ` + ${tr("select_or_create_new")} +
` + + if(note.value != "none") { + body += ` +
+ ${tr("do_not_attach_note")} +
` + } + + for(const note of notes.items) { + body += ` +
+ ${escapeHtml(note.name)} +
+ ` + } + + body += `
` + } + } + + let frame = MessageBox(tr("select_note"), body, [tr("cancel")], [Function.noop]); + + document.querySelector(".ovk-diag-body").style.padding = "10px" +} \ No newline at end of file diff --git a/locales/en.strings b/locales/en.strings index 72bf67f8..0a5c02c6 100644 --- a/locales/en.strings +++ b/locales/en.strings @@ -404,6 +404,16 @@ "notes_list_one" = "$1 note found"; "notes_list_other" = "$1 notes found"; +"select_note" = "Selecting note"; +"no_notes" = "You don't have any notes"; + +"error_attaching_note" = "Error when attaching note"; + +"select_or_create_new" = "Select existing note or
create new one"; + +"notes_closed" = "You can't attach note to post, because only you can see them.
You can change it in settings."; +"do_not_attach_note" = "Do not attach note"; + /* Menus */ /* Note that is string need to fit into the "My Page" link */ diff --git a/locales/ru.strings b/locales/ru.strings index ce943e33..060819db 100644 --- a/locales/ru.strings +++ b/locales/ru.strings @@ -389,6 +389,16 @@ "notes_list_many" = "Найдено $1 заметок"; "notes_list_other" = "Найдено $1 заметок"; +"select_note" = "Выбор заметки"; +"no_notes" = "У вас нет ни одной заметки"; + +"error_attaching_note" = "Не удалось прикрепить заметку"; + +"select_or_create_new" = "Выберите существующую заметку или создайте новую"; + +"notes_closed" = "Вы не можете прикрепить заметку к записи, так как ваши заметки видны только вам.

Вы можете поменять это в настройках."; +"do_not_attach_note" = "Не прикреплять заметку"; + /* Menus */ "edit_button" = "ред.";