Compare commits

..

5 commits

Author SHA1 Message Date
Artemka
edab81e56b
Merge f575b71bb0 into 2e70a26283 2024-12-13 17:31:22 +03:00
n1rwana
2e70a26283
feat(api): reports (#959)
* API для отправки жалобы

* make compatible with vk api

---------

Co-authored-by: mrilyew <99399973+mrilyew@users.noreply.github.com>
2024-12-13 17:11:26 +03:00
veselcraft
29f4de2dab
fix(video): tweak ffmpeg args 2024-12-13 17:06:56 +03:00
mrilyew
0a1f717b45 fix(xss): fix #1181 2024-12-13 16:43:34 +03:00
veselcraft
198bf7472d
fix(datetime): adjust to timezone 2024-12-13 16:24:51 +03:00
10 changed files with 80 additions and 13 deletions

View file

@ -0,0 +1,53 @@
<?php declare(strict_types=1);
namespace openvk\VKAPI\Handlers;
use openvk\Web\Models\Entities\Report;
use openvk\Web\Models\Repositories\Reports as ReportsRepo;
final class Reports extends VKAPIRequestHandler
{
function add(int $owner_id = 0, string $comment = "", int $reason = 0, string $type = "", string $report_source = ""): int
{
$this->requireUser();
$this->willExecuteWriteAction();
$allowed_types = ["post", "photo", "video", "group", "comment", "note", "app", "user", "audio"];
if($type == "" || !in_array($type, $allowed_types)) {
$this->fail(100, "One of the parameters specified was missing or invalid: type should be ".implode(", ", $allowed_types));
}
if($owner_id <= 0) {
$this->fail(100, "One of the parameters specified was missing or invalid: Bad input");
}
if(mb_strlen($comment) === 0) {
$this->fail(100, "One of the parameters specified was missing or invalid: Comment can't be empty");
}
if($type == "user" && $owner_id == $this->getUser()->getId()) {
return 1;
}
if($this->getUser()->isBannedInSupport()) {
return 0;
}
if(sizeof(iterator_to_array((new ReportsRepo)->getDuplicates($type, $owner_id, NULL, $this->getUser()->getId()))) > 0) {
return 1;
}
try {
$report = new Report;
$report->setUser_id($this->getUser()->getId());
$report->setTarget_id($owner_id);
$report->setType($type);
$report->setReason($comment);
$report->setCreated(time());
$report->save();
} catch(\Throwable $e) {
$this->fail(-1, "Unknown error failed");
}
return 1;
}
}

View file

@ -13,7 +13,7 @@ Move-Item $file $temp
# video stub logic was implicitly deprecated, so we start processing at once # video stub logic was implicitly deprecated, so we start processing at once
ffmpeg -i $temp -ss 00:00:01.000 -vframes 1 "$dir$hashT/$hash.gif" ffmpeg -i $temp -ss 00:00:01.000 -vframes 1 "$dir$hashT/$hash.gif"
ffmpeg -i $temp -c:v libx264 -q:v 7 -c:a libmp3lame -q:a 4 -tune zerolatency -vf "scale=480:-1,setsar=1" -y $temp2 ffmpeg -i $temp -c:v libx264 -q:v 7 -c:a libmp3lame -q:a 4 -tune zerolatency -vf "scale=iw*min(1\,if(gt(iw\,ih)\,640/iw\,(640*sar)/ih)):(floor((ow/dar)/2))*2" -y $temp2
Move-Item $temp2 "$dir$hashT/$hash.mp4" Move-Item $temp2 "$dir$hashT/$hash.mp4"
Remove-Item $temp Remove-Item $temp

View file

@ -3,7 +3,7 @@ tmpfile="$RANDOM-$(date +%s%N)"
cp $2 "/tmp/vid_$tmpfile.bin" cp $2 "/tmp/vid_$tmpfile.bin"
nice ffmpeg -i "/tmp/vid_$tmpfile.bin" -ss 00:00:01.000 -vframes 1 $3${4:0:2}/$4.gif nice ffmpeg -i "/tmp/vid_$tmpfile.bin" -ss 00:00:01.000 -vframes 1 $3${4:0:2}/$4.gif
nice -n 20 ffmpeg -i "/tmp/vid_$tmpfile.bin" -c:v libx264 -q:v 7 -c:a libmp3lame -q:a 4 -tune zerolatency -vf "scale=480:-1,setsar=1" -y "/tmp/ffmOi$tmpfile.mp4" nice -n 20 ffmpeg -i "/tmp/vid_$tmpfile.bin" -c:v libx264 -q:v 7 -c:a libmp3lame -q:a 4 -tune zerolatency -vf "scale=iw*min(1\,if(gt(iw\,ih)\,640/iw\,(640*sar)/ih)):(floor((ow/dar)/2))*2" -y "/tmp/ffmOi$tmpfile.mp4"
rm -rf $3${4:0:2}/$4.mp4 rm -rf $3${4:0:2}/$4.mp4
mv "/tmp/ffmOi$tmpfile.mp4" $3${4:0:2}/$4.mp4 mv "/tmp/ffmOi$tmpfile.mp4" $3${4:0:2}/$4.mp4

View file

@ -90,6 +90,9 @@ final class ReportPresenter extends OpenVKPresenter
if(!$id) if(!$id)
exit(json_encode([ "error" => tr("error_segmentation") ])); exit(json_encode([ "error" => tr("error_segmentation") ]));
if ($this->queryParam("type") === "user" && $id === $this->user->id)
exit(json_encode([ "error" => "You can't report yourself" ]));
if(in_array($this->queryParam("type"), ["post", "photo", "video", "group", "comment", "note", "app", "user", "audio"])) { if(in_array($this->queryParam("type"), ["post", "photo", "video", "group", "comment", "note", "app", "user", "audio"])) {
if (count(iterator_to_array($this->reports->getDuplicates($this->queryParam("type"), $id, NULL, $this->user->id))) <= 0) { if (count(iterator_to_array($this->reports->getDuplicates($this->queryParam("type"), $id, NULL, $this->user->id))) <= 0) {
$report = new Report; $report = new Report;

View file

@ -164,11 +164,11 @@
<tbody> <tbody>
<tr> <tr>
<td width="120" valign="top"><span class="nobold">${tr('performer')}:</span></td> <td width="120" valign="top"><span class="nobold">${tr('performer')}:</span></td>
<td><input value='${audio_element.info.performer}' name="performer" type="text" autocomplete="off" maxlength="80" /></td> <td><input value='${escapeHtml(audio_element.info.performer)}' name="performer" type="text" autocomplete="off" maxlength="80" /></td>
</tr> </tr>
<tr> <tr>
<td width="120" valign="top"><span class="nobold">${tr('audio_name')}:</span></td> <td width="120" valign="top"><span class="nobold">${tr('audio_name')}:</span></td>
<td><input type="text" value='${audio_element.info.name}' name="name" autocomplete="off" maxlength="80" /></td> <td><input type="text" value='${escapeHtml(audio_element.info.name)}' name="name" autocomplete="off" maxlength="80" /></td>
</tr> </tr>
<tr> <tr>
<td width="120" valign="top"><span class="nobold">${tr('genre')}:</span></td> <td width="120" valign="top"><span class="nobold">${tr('genre')}:</span></td>
@ -178,7 +178,7 @@
</tr> </tr>
<tr> <tr>
<td width="120" valign="top"><span class="nobold">${tr('lyrics')}:</span></td> <td width="120" valign="top"><span class="nobold">${tr('lyrics')}:</span></td>
<td><textarea name="lyrics" style="resize: vertical;max-height: 300px;">${audio_element.info.lyrics}</textarea></td> <td><textarea name="lyrics" style="resize: vertical;max-height: 300px;">${escapeHtml(audio_element.info.lyrics)}</textarea></td>
</tr> </tr>
<tr> <tr>
<td width="120" valign="top"></td> <td width="120" valign="top"></td>

View file

@ -16,7 +16,7 @@
{elseif $type == "group" || $type == "user"} {elseif $type == "group" || $type == "user"}
{include "../components/group.xml", group => $object, isUser => $type == "user"} {include "../components/group.xml", group => $object, isUser => $type == "user"}
{elseif $type == "comment"} {elseif $type == "comment"}
{include "../components/comment.xml", comment => $object, timeOnly => true, linkWithPost => true} {include "../components/comment.xml", comment => $object, timeOnly => true, correctLink => true}
{elseif $type == "note"} {elseif $type == "note"}
{include "./content/note.xml", note => $object} {include "./content/note.xml", note => $object}
{elseif $type == "app"} {elseif $type == "app"}

View file

@ -1,5 +1,6 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
namespace openvk\Web\Util; namespace openvk\Web\Util;
use Chandler\Session\Session;
class DateTime class DateTime
{ {
@ -21,17 +22,19 @@ class DateTime
$then = date_create("@" . $this->timestamp); $then = date_create("@" . $this->timestamp);
$now = date_create(); $now = date_create();
$diff = date_diff($now, $then); $diff = date_diff($now, $then);
$sessionOffset = intval(Session::i()->get("_timezoneOffset"));
if($diff->invert === 0) if($diff->invert === 0)
return ovk_strftime_safe("%e %B %Y ", $this->timestamp) . tr("time_at_sp") . ovk_strftime_safe(" %R", $this->timestamp); return ovk_strftime_safe("%e %B %Y ", $this->timestamp) . tr("time_at_sp") . ovk_strftime_safe(" %R", $this->timestamp);
if($this->timestamp >= strtotime("midnight")) { # Today if(($this->timestamp + $sessionOffset) >= (strtotime("midnight") + $sessionOffset)) { # Today
if($diff->h >= 1) if($diff->h >= 1)
return tr("time_today") . tr("time_at_sp") . ovk_strftime_safe(" %R", $this->timestamp); return tr("time_today") . tr("time_at_sp") . ovk_strftime_safe(" %R", $this->timestamp);
else if($diff->i < 2) else if($diff->i < 2)
return tr("time_just_now"); return tr("time_just_now");
else else
return $diff->i === 5 ? tr("time_exactly_five_minutes_ago") : tr("time_minutes_ago", $diff->i); return $diff->i === 5 ? tr("time_exactly_five_minutes_ago") : tr("time_minutes_ago", $diff->i);
} else if($this->timestamp >= strtotime("-1day midnight")) { # Yesterday } else if(($this->timestamp + $sessionOffset) >= (strtotime("-1day midnight") + $sessionOffset)) { # Yesterday
return tr("time_yesterday") . tr("time_at_sp") . ovk_strftime_safe(" %R", $this->timestamp); return tr("time_yesterday") . tr("time_at_sp") . ovk_strftime_safe(" %R", $this->timestamp);
} else if(ovk_strftime_safe("%Y", $this->timestamp) === ovk_strftime_safe("%Y", time())) { # In this year } else if(ovk_strftime_safe("%Y", $this->timestamp) === ovk_strftime_safe("%Y", time())) { # In this year
return ovk_strftime_safe("%e %h ", $this->timestamp) . tr("time_at_sp") . ovk_strftime_safe(" %R", $this->timestamp); return ovk_strftime_safe("%e %h ", $this->timestamp) . tr("time_at_sp") . ovk_strftime_safe(" %R", $this->timestamp);

View file

@ -1306,12 +1306,12 @@ u(document).on("click", ".musicIcon.edit-icon", (e) => {
MessageBox(tr("edit_audio"), ` MessageBox(tr("edit_audio"), `
<div> <div>
${tr("performer")} ${tr("performer")}
<input name="performer" maxlength="256" type="text" value="${performer}"> <input name="performer" maxlength="256" type="text" value="${escapeHtml(performer)}">
</div> </div>
<div style="margin-top: 11px"> <div style="margin-top: 11px">
${tr("audio_name")} ${tr("audio_name")}
<input name="name" maxlength="256" type="text" value="${name}"> <input name="name" maxlength="256" type="text" value="${escapeHtml(name)}">
</div> </div>
<div style="margin-top: 11px"> <div style="margin-top: 11px">
@ -1359,7 +1359,7 @@ u(document).on("click", ".musicIcon.edit-icon", (e) => {
e.target.setAttribute("data-performer", escapeHtml(response.new_info.performer)) e.target.setAttribute("data-performer", escapeHtml(response.new_info.performer))
e.target.setAttribute("data-title", escapeHtml(response.new_info.name)) e.target.setAttribute("data-title", escapeHtml(response.new_info.name))
e.target.setAttribute("data-lyrics", response.new_info.lyrics_unformatted) e.target.setAttribute("data-lyrics", escapeHtml(response.new_info.lyrics_unformatted))
e.target.setAttribute("data-explicit", Number(response.new_info.explicit)) e.target.setAttribute("data-explicit", Number(response.new_info.explicit))
e.target.setAttribute("data-searchable", Number(!response.new_info.unlisted)) e.target.setAttribute("data-searchable", Number(!response.new_info.unlisted))
player.setAttribute("data-genre", response.new_info.genre) player.setAttribute("data-genre", response.new_info.genre)
@ -1374,7 +1374,7 @@ u(document).on("click", ".musicIcon.edit-icon", (e) => {
} else { } else {
player.insertAdjacentHTML("beforeend", ` player.insertAdjacentHTML("beforeend", `
<div class="lyrics"> <div class="lyrics">
${response.new_info.lyrics} ${escapeHtml(response.new_info.lyrics)}
</div> </div>
`) `)

View file

@ -2579,7 +2579,7 @@ async function changeStatus() {
document.querySelector("#page_status_text").innerHTML = `[ ${tr("change_status")} ]`; document.querySelector("#page_status_text").innerHTML = `[ ${tr("change_status")} ]`;
document.querySelector("#page_status_text").className = "edit_link page_status_edit_button"; document.querySelector("#page_status_text").className = "edit_link page_status_edit_button";
} else { } else {
document.querySelector("#page_status_text").innerHTML = status; document.querySelector("#page_status_text").innerHTML = escapeHtml(status);
document.querySelector("#page_status_text").className = "page_status page_status_edit_button"; document.querySelector("#page_status_text").className = "page_status page_status_edit_button";
} }

View file

@ -234,6 +234,10 @@ window.router = new class {
} }
u(document).on('click', 'a', async (e) => { u(document).on('click', 'a', async (e) => {
if(e.defaultPrevented) {
return
}
const target = u(e.target).closest('a') const target = u(e.target).closest('a')
const dom_url = target.attr('href') const dom_url = target.attr('href')
const id = target.attr('id') const id = target.attr('id')
@ -289,6 +293,10 @@ u(document).on('click', 'a', async (e) => {
}) })
u(document).on('submit', 'form', async (e) => { u(document).on('submit', 'form', async (e) => {
if(e.defaultPrevented) {
return
}
if(u('#ajloader').hasClass('shown')) { if(u('#ajloader').hasClass('shown')) {
e.preventDefault() e.preventDefault()
return return