Merge branch 'newapis' of https://github.com/lalka2016/openvkuh into newapis

This commit is contained in:
lalka2016 2023-05-27 22:15:27 +03:00
commit 686a4d0471
20 changed files with 242 additions and 75 deletions

39
ServiceAPI/Groups.php Normal file
View file

@ -0,0 +1,39 @@
<?php declare(strict_types=1);
namespace openvk\ServiceAPI;
use openvk\Web\Models\Entities\User;
use openvk\Web\Models\Repositories\Clubs;
class Groups implements Handler
{
protected $user;
protected $groups;
function __construct(?User $user)
{
$this->user = $user;
$this->groups = new Clubs;
}
function getWriteableClubs(callable $resolve, callable $reject)
{
$clubs = [];
$wclubs = $this->groups->getWriteableClubs($this->user->getId());
$count = $this->groups->getWriteableClubsCount($this->user->getId());
if(!$count) {
$reject("You don't have any groups with write access");
return;
}
foreach($wclubs as $club) {
$clubs[] = [
"name" => $club->getName(),
"id" => $club->getId(),
"avatar" => $club->getAvatarUrl() # если в овк когда-нибудь появится крутой список с аватарками, то можно использовать это поле
];
}
$resolve($clubs);
}
}

View file

@ -476,25 +476,38 @@ final class Wall extends VKAPIRequestHandler
return (object)["post_id" => $post->getVirtualId()];
}
function repost(string $object, string $message = "") {
function repost(string $object, string $message = "", int $group_id = 0) {
$this->requireUser();
$this->willExecuteWriteAction();
$postArray;
if(preg_match('/wall((?:-?)[0-9]+)_([0-9]+)/', $object, $postArray) == 0)
$this->fail(100, "One of the parameters specified was missing or invalid: object is incorrect");
$post = (new PostsRepo)->getPostById((int) $postArray[1], (int) $postArray[2]);
if(!$post || $post->isDeleted()) $this->fail(100, "One of the parameters specified was missing or invalid");
$nPost = new Post;
$nPost->setOwner($this->user->getId());
$nPost->setWall($this->user->getId());
if($group_id > 0) {
$club = (new ClubsRepo)->get($group_id);
if(!$club)
$this->fail(42, "Invalid group");
if(!$club->canBeModifiedBy($this->user))
$this->fail(16, "Access to group denied");
$nPost->setWall($group_id * -1);
} else {
$nPost->setWall($this->user->getId());
}
$nPost->setContent($message);
$nPost->setApi_Source_Name($this->getPlatform());
$nPost->save();
$nPost->attach($post);
if($post->getOwner(false)->getId() !== $this->user->getId() && !($post->getOwner() instanceof Club))
(new RepostNotification($post->getOwner(false), $post, $this->user->identity))->emit();
@ -506,6 +519,7 @@ final class Wall extends VKAPIRequestHandler
];
}
function getComments(int $owner_id, int $post_id, bool $need_likes = true, int $offset = 0, int $count = 10, string $fields = "sex,screen_name,photo_50,photo_100,online_info,online", string $sort = "asc", bool $extended = false) {
$this->requireUser();

View file

@ -195,11 +195,11 @@ class Video extends Media
$this->save();
}
static function fastMake(int $owner, string $description = "", array $file, bool $unlisted = true, bool $anon = false): Video
static function fastMake(int $owner, string $name = "Unnamed Video.ogv", string $description = "", array $file, bool $unlisted = true, bool $anon = false): Video
{
$video = new Video;
$video->setOwner($owner);
$video->setName("Unnamed Video.ogv");
$video->setName(ovk_proc_strtr($name, 61));
$video->setDescription(ovk_proc_strtr($description, 300));
$video->setAnonymous($anon);
$video->setCreated(time());

View file

@ -1,7 +1,7 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Repositories;
use openvk\Web\Models\Entities\Club;
use openvk\Web\Models\Repositories\Aliases;
use openvk\Web\Models\Entities\{Club, Manager};
use openvk\Web\Models\Repositories\{Aliases, Users};
use Nette\Database\Table\ActiveRow;
use Chandler\Database\DatabaseConnection;
@ -9,11 +9,13 @@ class Clubs
{
private $context;
private $clubs;
private $coadmins;
function __construct()
{
$this->context = DatabaseConnection::i()->getContext();
$this->clubs = $this->context->table("groups");
$this->context = DatabaseConnection::i()->getContext();
$this->clubs = $this->context->table("groups");
$this->coadmins = $this->context->table("group_coadmins");
}
private function toClub(?ActiveRow $ar): ?Club
@ -70,6 +72,26 @@ class Clubs
];
*/
}
function getWriteableClubs(int $id): \Traversable
{
$result = $this->clubs->where("owner", $id);
$coadmins = $this->coadmins->where("user", $id);
foreach($result as $entry) {
yield new Club($entry);
}
foreach($coadmins as $coadmin) {
$cl = new Manager($coadmin);
yield $cl->getClub();
}
}
function getWriteableClubsCount(int $id): int
{
return sizeof($this->clubs->where("owner", $id)) + sizeof($this->coadmins->where("user", $id));
}
use \Nette\SmartObject;
}

View file

@ -74,7 +74,7 @@ final class CommentPresenter extends OpenVKPresenter
}
if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK) {
$video = Video::fastMake($this->user->id, $this->postParam("text"), $_FILES["_vid_attachment"]);
$video = Video::fastMake($this->user->id, $_FILES["_vid_attachment"]["name"], $this->postParam("text"), $_FILES["_vid_attachment"]);
}
} catch(ISE $ex) {
$this->flashFail("err", "Не удалось опубликовать комментарий", "Файл медиаконтента повреждён или слишком велик.");

View file

@ -105,7 +105,7 @@ final class TopicsPresenter extends OpenVKPresenter
}
if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK) {
$video = Video::fastMake($this->user->id, $this->postParam("text"), $_FILES["_vid_attachment"]);
$video = Video::fastMake($this->user->id, $_FILES["_vid_attachment"]["name"], $this->postParam("text"), $_FILES["_vid_attachment"]);
}
} catch(ISE $ex) {
$this->flash("err", "Не удалось опубликовать комментарий", "Файл медиаконтента повреждён или слишком велик.");

View file

@ -258,7 +258,7 @@ final class WallPresenter extends OpenVKPresenter
}
if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK)
$video = Video::fastMake($this->user->id, $this->postParam("text"), $_FILES["_vid_attachment"], $anon);
$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) {
@ -363,21 +363,52 @@ final class WallPresenter extends OpenVKPresenter
$this->assertNoCSRF();
$post = $this->posts->getPostById($wall, $post_id);
if(!$post || $post->isDeleted()) $this->notFound();
if(!$post || $post->isDeleted())
$this->notFound();
$where = $this->postParam("type") ?? "wall";
$groupId = NULL;
$flags = 0;
if($where == "group")
$groupId = $this->postParam("groupId");
if(!is_null($this->user)) {
$nPost = new Post;
$nPost->setOwner($this->user->id);
$nPost->setWall($this->user->id);
if($where == "wall") {
$nPost->setOwner($this->user->id);
$nPost->setWall($this->user->id);
} elseif($where == "group") {
$nPost->setOwner($this->user->id);
$club = (new Clubs)->get((int)$groupId);
if(!$club || !$club->canBeModifiedBy($this->user->identity))
$this->notFound();
if($this->postParam("asGroup") == 1)
$flags |= 0b10000000;
if($this->postParam("signed") == 1)
$flags |= 0b01000000;
$nPost->setWall($groupId * -1);
}
$nPost->setContent($this->postParam("text"));
$nPost->setFlags($flags);
$nPost->save();
$nPost->attach($post);
if($post->getOwner(false)->getId() !== $this->user->identity->getId() && !($post->getOwner() instanceof Club))
(new RepostNotification($post->getOwner(false), $post, $this->user->identity))->emit();
};
$this->returnJson(["wall_owner" => $this->user->identity->getId()]);
$this->returnJson([
"wall_owner" => $where == "wall" ? $this->user->identity->getId() : $groupId * -1
]);
}
function renderDelete(int $wall, int $post_id): void

View file

@ -458,7 +458,7 @@
</tr>
<tr>
<td class="e">Initial hosting</td>
<td class="v">Ilya Prokopenko (dsrev) and Celestora</td>
<td class="v">Lumaeris and Celestora</td>
</tr>
<tr>
<td class="e">Initial bug-tracker hosting</td>
@ -492,7 +492,7 @@
<td>
kovaltim, Vladimir Lapskiy (0x7d5), Alexander Minkin (WerySkok), Polina Katunina (RousPhaul), veth,
Egor Shevchenko, Vadim Korovin (yuni), Ash Defenders,
Pavel Silaev, Dmitriy Daemon, Ilya Prokopenko (dsrev),
Pavel Silaev, Dmitriy Daemon, Lumaeris,
cmed404 and unknown tester, who disappeared shortly after trying to upload post with cat.
</td>
</tr>

View file

@ -129,12 +129,12 @@
</td>
<td>
{_registration_disabled_info}
{if OPENVK_ROOT_CONF['openvk']['preferences']['registration']['reason']}
{if OPENVK_ROOT_CONF['openvk']['preferences']['registration']['disablingReason']}
<br/>
<br/>
{_admin_banned_link_reason}:
<br>
<b>{php echo OPENVK_ROOT_CONF['openvk']['preferences']['registration']['reason']}</b>
<b>{php echo OPENVK_ROOT_CONF['openvk']['preferences']['registration']['disablingReason']}</b>
{/if}
</td>
</tr>

View file

@ -98,9 +98,9 @@
<a n:if="!($forceNoCommentsLink ?? false) && $commentsCount == 0" href="javascript:expand_comment_textarea({$commentTextAreaId})">{_comment}</a>
<div class="like_wrap">
<a n:if="!($forceNoShareLink ?? false)" class="post-share-button" href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')">
<a n:if="!($forceNoShareLink ?? false)" id="reposts{$post->getPrettyId()}" class="post-share-button" href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')">
<div class="repost-icon" style="opacity: 0.4;"></div>
<span class="likeCnt">{if $post->getRepostCount() > 0}{$post->getRepostCount()}{/if}</span>
<span class="likeCnt" id="repostsCount{$post->getPrettyId()}">{if $post->getRepostCount() > 0}{$post->getRepostCount()}{/if}</span>
</a>
{if !($forceNoLike ?? false)}

View file

@ -111,10 +111,10 @@
&nbsp;|&nbsp;
{/if}
<a n:if="!($forceNoShareLink ?? false)" class="post-share-button" {ifset $thisUser} href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')"{/ifset}>
<a n:if="!($forceNoShareLink ?? false)" id="reposts{$post->getPrettyId()}" class="post-share-button" {ifset $thisUser} href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')"{/ifset}>
{_share}
{if $post->getRepostCount() > 0}
(<b>{$post->getRepostCount()}</b>)
(<b id="repostsCount{$post->getPrettyId()}">{$post->getRepostCount()}</b>)
{/if}
</a>

View file

@ -176,7 +176,7 @@ time.bsdn_timeFull {
border: 1px solid #908f90;
width: 232px;
height: 169px;
font-size: 15px;
font-size: 13px;
box-sizing: border-box;
}

View file

@ -1,3 +1,4 @@

function expand_wall_textarea(id) {
var el = document.getElementById('post-buttons'+id);
var wi = document.getElementById('wall-post-input'+id);
@ -65,7 +66,6 @@ function toggleMenu(id) {
});
}
}
document.addEventListener("DOMContentLoaded", function() { //BEGIN
u("#_photoDelete").on("click", function(e) {
@ -88,7 +88,6 @@ document.addEventListener("DOMContentLoaded", function() { //BEGIN
return e.preventDefault();
});
/* @rem-pai why this func wasn't named as "#_deleteDialog"? It looks universal IMO */
u("#_noteDelete").on("click", function(e) {
@ -170,28 +169,72 @@ document.addEventListener("DOMContentLoaded", function() { //BEGIN
}); //END ONREADY DECLS
function repostPost(id, hash) {
uRepostMsgTxt = tr('your_comment') + ": <textarea id='uRepostMsgInput_"+id+"'></textarea><br/><br/>";
MessageBox(tr('share'), uRepostMsgTxt, [tr('send'), tr('cancel')], [
(function() {
text = document.querySelector("#uRepostMsgInput_"+id).value;
hash = encodeURIComponent(hash);
xhr = new XMLHttpRequest();
xhr.open("POST", "/wall"+id+"/repost?hash="+hash, true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.onload = (function() {
async function repostPost(id, hash) {
uRepostMsgTxt = `
<b>${tr('auditory')}:</b> <br/>
<input type="radio" name="type" onchange="signs.setAttribute('hidden', 'hidden');document.getElementById('groupId').setAttribute('hidden', 'hidden')" value="wall" checked>${tr("in_wall")}<br/>
<input type="radio" name="type" onchange="signs.removeAttribute('hidden');document.getElementById('groupId').removeAttribute('hidden')" value="group" id="group">${tr("in_group")}<br/>
<select style="width:50%;" id="groupId" name="groupId" hidden>
</select><br/>
<b>${tr('your_comment')}:</b>
<textarea id='uRepostMsgInput_${id}'></textarea>
<div id="signs" hidden>
<label><input onchange="signed.checked ? signed.checked = false : null" type="checkbox" id="asgroup" name="asGroup">${tr('post_as_group')}</label><br>
<label><input onchange="asgroup.checked = true" type="checkbox" id="signed" name="signed">${tr('add_signature')}</label>
</div>
<br/><br/>`;
let clubs = [];
repostsCount = document.getElementById("repostsCount"+id)
prevVal = repostsCount != null ? Number(repostsCount.innerHTML) : 0;
MessageBox(tr('share'), uRepostMsgTxt, [tr('send'), tr('cancel')], [
(function() {
text = document.querySelector("#uRepostMsgInput_"+id).value;
type = "user";
radios = document.querySelectorAll('input[name="type"]')
for(const r of radios)
{
if(r.checked)
{
type = r.value;
break;
}
}
groupId = document.querySelector("#groupId").value;
asGroup = asgroup.checked == true ? 1 : 0;
signed = signed.checked == true ? 1 : 0;
hash = encodeURIComponent(hash);
xhr = new XMLHttpRequest();
xhr.open("POST", "/wall"+id+"/repost?hash="+hash, true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.onload = (function() {
if(xhr.responseText.indexOf("wall_owner") === -1)
MessageBox(tr('error'), tr('error_repost_fail'), [tr('ok')], [Function.noop]);
else {
let jsonR = JSON.parse(xhr.responseText);
MessageBox(tr('error'), tr('error_repost_fail'), [tr('ok')], [Function.noop]);
else {
let jsonR = JSON.parse(xhr.responseText);
NewNotification(tr('information_-1'), tr('shared_succ'), null, () => {window.location.href = "/wall" + jsonR.wall_owner});
}
});
xhr.send('text=' + encodeURI(text));
}),
Function.noop
]);
repostsCount != null ?
repostsCount.innerHTML = prevVal+1 :
document.getElementById("reposts"+id).insertAdjacentHTML("beforeend", "(<b id='repostsCount"+id+"'>1</b>)") //для старого вида постов
}
});
xhr.send('text='+encodeURI(text) + '&type='+type + '&groupId='+groupId + "&asGroup="+asGroup + "&signed="+signed);
}),
Function.noop
]);
try
{
clubs = await API.Groups.getWriteableClubs();
for(const el of clubs) {
document.getElementById("groupId").insertAdjacentHTML("beforeend", `<option value="${el.id}">${escapeHtml(el.name)}</option>`)
}
} catch(rejection) {
console.error(rejection)
document.getElementById("group").setAttribute("disabled", "disabled")
}
}
function setClubAdminComment(clubId, adminId, hash) {
@ -535,4 +578,4 @@ $(document).on("scroll", () => {
$(".floating_sidebar")[0].classList.remove("hide_anim");
}, 250);
}
})
})

View file

@ -26,14 +26,14 @@ function _bsdnTpl(name, author) {
<span class="bsdn_contextMenuElement">OpenVK BSDN///Player 0.1</span>
<hr/>
<span class="bsdn_contextMenuElement">Developers:</span>
<span class="bsdn_contextMenuElement" onclick="window.location.assign('https://github.com/celestora');">
- celstora
</span>
<span class="bsdn_contextMenuElement" onclick="window.location.assign('https://github.com/openvk/openvk/issues');">
- Report a problem...
<span class="bsdn_contextMenuElement" onclick="window.open('https://github.com/celestora');">
- celestora
</span>
<hr/>
<span class="bsdn_contextMenuElement" onclick="confirm('эм это шутка');">About Adobe Flash Player...</span>
<span class="bsdn_contextMenuElement" onclick="window.open('https://github.com/openvk/openvk/issues/new');">
Report a problem...
</span>
<span class="bsdn_contextMenuElement" onclick="window.open('https://www.youtube.com/watch?v=4Hq53bN34_w');">About Adobe Flash Player...</span>
</div>
<div class="bsdn_controls">

View file

@ -175,6 +175,9 @@
"pinned" = "pinned";
"comments_tip" = "Be first, who leaves a comment at this post!";
"your_comment" = "Your comment";
"auditory" = "Auditory";
"in_wall" = "to user's wall";
"in_group" = "to group";
"shown" = "Shown";
"x_out_of" = "$1 of";
"wall_zero" = "no posts";

View file

@ -157,6 +157,9 @@
"pinned" = "закреплено";
"comments_tip" = "Будьте первым, кто оставит комментарий!";
"your_comment" = "Ваш комментарий";
"auditory" = "Аудитория";
"in_wall" = "на стену";
"in_group" = "в группу";
"shown" = "Показано";
"x_out_of" = "$1 из";
"wall_zero" = "нет записей";

View file

@ -159,6 +159,9 @@
"pinned" = "прикріплено";
"comments_tip" = "Будьте першим, хто залишить коментар!";
"your_comment" = "Ваш коментар";
"auditory" = "Аудиторія";
"in_wall" = "на стіну";
"in_group" = "у групу";
"shown" = "Показано";
"x_out_of" = "$1 з";
"wall_zero" = "немає записів";

View file

@ -37,9 +37,9 @@ openvk:
autoban: true
registration:
enable: true
reason: "" # reason for disabling registration
disablingReason: ""
support:
supportName: "Moderator"
supportName: "Agent"
adminAccount: 1 # Change this ok
fastAnswers:
- "This is a list of quick answers to common questions for support. Post your responses here and agents can send it quickly with just 3 clicks"
@ -125,9 +125,9 @@ openvk:
token: "TOKEN_HERE"
helpdeskChat: ""
eventDB:
enable: false # Better enable this
enable: true
database:
dsn: "mysql:unix_socket=/tmp/mysql.sock;dbname=openvk-eventdb"
dsn: "mysql:unix_host=localhost;dbname=openvk-eventdb" # or unix_socket=/tmp/mysql.sock
user: "root"
password: "DATABASE_PASSWORD"
notificationsBroker:

View file

@ -65,6 +65,15 @@ hr {
background-color: #2c2640;
}
.bsdn_contextMenu {
background-color: #1f1a2c;
border-color: #2c2640;
}
.bsdn_contextMenuElement:hover {
background-color: #29223a;
}
#ovkDraw .literally .lc-picker, .literally .lc-options.horz-toolbar, .mb_tab#active {
background-color: #453e5e;
}
@ -128,11 +137,11 @@ h4, .content_title_expanded, .summaryBar .summary, .content_title_unexpanded {
}
.content_title_expanded {
background-image: url("/themepack/midnight/0.0.2.4/resource/flex_arrow_open.png") !important;
background-image: url("/themepack/midnight/0.0.2.5/resource/flex_arrow_open.png") !important;
}
.content_title_unexpanded {
background-image: url("/themepack/midnight/0.0.2.4/resource/flex_arrow_shut.gif") !important;
background-image: url("/themepack/midnight/0.0.2.5/resource/flex_arrow_shut.gif") !important;
}
.ovk-video > .preview, .video-preview {
@ -154,17 +163,17 @@ h4, .content_title_expanded, .summaryBar .summary, .content_title_unexpanded {
.page_yellowheader {
color: #c6d2e8;
background-image: url("/themepack/midnight/0.0.2.4/resource/header_purple.png") !important;
background-image: url("/themepack/midnight/0.0.2.5/resource/header_purple.png") !important;
background-color: #231f34;
border-color: #231f34;
}
.page_header {
background-image: url("/themepack/midnight/0.0.2.4/resource/header.png") !important;
background-image: url("/themepack/midnight/0.0.2.5/resource/header.png") !important;
}
.page_custom_header {
background-image: url("/themepack/midnight/0.0.2.4/resource/header_custom.png") !important;
background-image: url("/themepack/midnight/0.0.2.5/resource/header_custom.png") !important;
}
.page_yellowheader span, .page_yellowheader a {
@ -184,11 +193,11 @@ form[action="/search"] > input, .header_search_input, textarea, input[type="text
}
input[type="checkbox"] {
background-image: url("/themepack/midnight/0.0.2.4/resource/checkbox.png") !important;
background-image: url("/themepack/midnight/0.0.2.5/resource/checkbox.png") !important;
}
input[type="radio"] {
background-image: url("/themepack/midnight/0.0.2.4/resource/radio.png") !important;
background-image: url("/themepack/midnight/0.0.2.5/resource/radio.png") !important;
}
.header_navigation .link {
@ -196,19 +205,19 @@ input[type="radio"] {
}
.heart {
background-image: url("/themepack/midnight/0.0.2.4/resource/like.gif") !important;
background-image: url("/themepack/midnight/0.0.2.5/resource/like.gif") !important;
}
.pinned-mark, .post-author .pin {
background-image: url("/themepack/midnight/0.0.2.4/resource/pin.png") !important;
background-image: url("/themepack/midnight/0.0.2.5/resource/pin.png") !important;
}
.repost-icon {
background-image: url("/themepack/midnight/0.0.2.4/resource/published.gif") !important;
background-image: url("/themepack/midnight/0.0.2.5/resource/published.gif") !important;
}
.post-author .delete {
background-image: url("/themepack/midnight/0.0.2.4/resource/input_clear.gif") !important;
background-image: url("/themepack/midnight/0.0.2.5/resource/input_clear.gif") !important;
}
.user-alert {

View file

@ -1,5 +1,5 @@
id: midnight
version: "0.0.2.4"
version: "0.0.2.5"
openvk_version: 0
enabled: 1
metadata:
@ -8,5 +8,5 @@ metadata:
en: "OpenVK Midnight"
ru: "OpenVK Midnight"
uk: "OpenVK Midnight"
author: "Ilya Prokopenko"
author: "Lumaeris"
description: "A dark theme for OpenVK"