mirror of
https://github.com/openvk/openvk
synced 2024-12-23 00:51:03 +03:00
Compare commits
6 commits
48ccd7ef43
...
a714a0aa16
Author | SHA1 | Date | |
---|---|---|---|
|
a714a0aa16 | ||
|
bec9079e36 | ||
|
2e70a26283 | ||
|
29f4de2dab | ||
|
0a1f717b45 | ||
|
198bf7472d |
40 changed files with 1017 additions and 34 deletions
|
@ -228,4 +228,72 @@ final class Account extends VKAPIRequestHandler
|
||||||
|
|
||||||
return (object) ['votes' => $this->getUser()->getCoins()];
|
return (object) ['votes' => $this->getUser()->getCoins()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ban(int $owner_id): int
|
||||||
|
{
|
||||||
|
$this->requireUser();
|
||||||
|
$this->willExecuteWriteAction();
|
||||||
|
|
||||||
|
if($owner_id < 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if($owner_id == $this->getUser()->getId())
|
||||||
|
$this->fail(15, "Access denied: cannot blacklist yourself");
|
||||||
|
|
||||||
|
$config_limit = OPENVK_ROOT_CONF['openvk']['preferences']['blacklists']['limit'] ?? 100;
|
||||||
|
$user_blocks = $this->getUser()->getBlacklistSize();
|
||||||
|
if(($user_blocks + 1) > $config_limit)
|
||||||
|
$this->fail(-7856, "Blacklist limit exceeded");
|
||||||
|
|
||||||
|
$entity = get_entity_by_id($owner_id);
|
||||||
|
if(!$entity || $entity->isDeleted())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if($entity->isBlacklistedBy($this->getUser()))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
$this->getUser()->addToBlacklist($entity);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function unban(int $owner_id): int
|
||||||
|
{
|
||||||
|
$this->requireUser();
|
||||||
|
$this->willExecuteWriteAction();
|
||||||
|
|
||||||
|
if($owner_id < 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if($owner_id == $this->getUser()->getId())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
$entity = get_entity_by_id($owner_id);
|
||||||
|
if(!$entity || $entity->isDeleted())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(!$entity->isBlacklistedBy($this->getUser()))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
$this->getUser()->removeFromBlacklist($entity);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBanned(int $offset = 0, int $count = 100, string $fields = ""): object
|
||||||
|
{
|
||||||
|
$this->requireUser();
|
||||||
|
|
||||||
|
$result = (object)[
|
||||||
|
'count' => $this->getUser()->getBlacklistSize(),
|
||||||
|
'items' => [],
|
||||||
|
];
|
||||||
|
$banned = $this->getUser()->getBlacklist($offset, $count);
|
||||||
|
foreach($banned as $ban) {
|
||||||
|
if(!$ban) continue;
|
||||||
|
$result->items[] = $ban->toVkApiStruct($this->getUser(), $fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
53
VKAPI/Handlers/Reports.php
Normal file
53
VKAPI/Handlers/Reports.php
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -266,6 +266,20 @@ final class Users extends VKAPIRequestHandler
|
||||||
case 'nickname':
|
case 'nickname':
|
||||||
$response[$i]->nickname = $usr->getPseudo();
|
$response[$i]->nickname = $usr->getPseudo();
|
||||||
break;
|
break;
|
||||||
|
case 'blacklisted_by_me':
|
||||||
|
if(!$authuser) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response[$i]->blacklisted_by_me = (int)$usr->isBlacklistedBy($this->getUser());
|
||||||
|
break;
|
||||||
|
case 'blacklisted':
|
||||||
|
if(!$authuser) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response[$i]->blacklisted = (int)$this->getUser()->isBlacklistedBy($usr);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -206,6 +206,9 @@ final class Wall extends VKAPIRequestHandler
|
||||||
if($post->isDeactivationMessage())
|
if($post->isDeactivationMessage())
|
||||||
$post_temp_obj->final_post = 1;
|
$post_temp_obj->final_post = 1;
|
||||||
|
|
||||||
|
if($post->getGeo())
|
||||||
|
$post_temp_obj->geo = $post->getVkApiGeo();
|
||||||
|
|
||||||
$items[] = $post_temp_obj;
|
$items[] = $post_temp_obj;
|
||||||
|
|
||||||
if ($from_id > 0)
|
if ($from_id > 0)
|
||||||
|
@ -321,14 +324,10 @@ final class Wall extends VKAPIRequestHandler
|
||||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Video) {
|
} else if ($attachment instanceof \openvk\Web\Models\Entities\Video) {
|
||||||
$attachments[] = $attachment->getApiStructure($this->getUser());
|
$attachments[] = $attachment->getApiStructure($this->getUser());
|
||||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Note) {
|
} else if ($attachment instanceof \openvk\Web\Models\Entities\Note) {
|
||||||
if(VKAPI_DECL_VER === '4.100') {
|
$attachments[] = [
|
||||||
$attachments[] = $attachment->toVkApiStruct();
|
'type' => 'note',
|
||||||
} else {
|
'note' => $attachment->toVkApiStruct()
|
||||||
$attachments[] = [
|
];
|
||||||
'type' => 'note',
|
|
||||||
'note' => $attachment->toVkApiStruct()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Audio) {
|
} else if ($attachment instanceof \openvk\Web\Models\Entities\Audio) {
|
||||||
$attachments[] = [
|
$attachments[] = [
|
||||||
"type" => "audio",
|
"type" => "audio",
|
||||||
|
@ -419,6 +418,9 @@ final class Wall extends VKAPIRequestHandler
|
||||||
if($post->isDeactivationMessage())
|
if($post->isDeactivationMessage())
|
||||||
$post_temp_obj->final_post = 1;
|
$post_temp_obj->final_post = 1;
|
||||||
|
|
||||||
|
if($post->getGeo())
|
||||||
|
$post_temp_obj->geo = $post->getVkApiGeo();
|
||||||
|
|
||||||
$items[] = $post_temp_obj;
|
$items[] = $post_temp_obj;
|
||||||
|
|
||||||
if ($from_id > 0)
|
if ($from_id > 0)
|
||||||
|
@ -493,7 +495,11 @@ final class Wall extends VKAPIRequestHandler
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function post(string $owner_id, string $message = "", string $copyright = "", int $from_group = 0, int $signed = 0, string $attachments = "", int $post_id = 0): object
|
function post(string $owner_id, string $message = "", string $copyright = "", int $from_group = 0, int $signed = 0, string $attachments = "", int $post_id = 0,
|
||||||
|
float $lat = NULL,
|
||||||
|
float $long = NULL,
|
||||||
|
string $place_name = ''
|
||||||
|
): object
|
||||||
{
|
{
|
||||||
$this->requireUser();
|
$this->requireUser();
|
||||||
$this->willExecuteWriteAction();
|
$this->willExecuteWriteAction();
|
||||||
|
@ -599,6 +605,45 @@ final class Wall extends VKAPIRequestHandler
|
||||||
} catch(\Throwable) {}
|
} catch(\Throwable) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*$info = file_get_contents("https://nominatim.openstreetmap.org/reverse?lat=${latitude}&lon=${longitude}&format=jsonv2", false, stream_context_create([
|
||||||
|
'http' => [
|
||||||
|
'method' => 'GET',
|
||||||
|
'header' => implode("\r\n", [
|
||||||
|
'User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.2 (KHTML, like Gecko) Chrome/22.0.1216.0 Safari/537.2',
|
||||||
|
"Referer: https://$_SERVER[SERVER_NAME]/"
|
||||||
|
])
|
||||||
|
]
|
||||||
|
]));
|
||||||
|
|
||||||
|
if ($info) {
|
||||||
|
$info = json_decode($info, true, JSON_UNESCAPED_UNICODE);
|
||||||
|
if (key_exists("place_id", $info)) {
|
||||||
|
$geo["name"] = $info["name"] ?? $info["display_name"];
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
if($lat && $long) {
|
||||||
|
if(($lat > 90 || $lat < -90) || ($long > 180 || $long < -180)) {
|
||||||
|
$this->fail(-785, 'Invalid geo info');
|
||||||
|
}
|
||||||
|
|
||||||
|
$latitude = number_format((float) $lat, 8, ".", '');
|
||||||
|
$longitude = number_format((float) $long, 8, ".", '');
|
||||||
|
|
||||||
|
$res = [
|
||||||
|
'lat' => $latitude,
|
||||||
|
'lng' => $longitude
|
||||||
|
];
|
||||||
|
if($place_name && mb_strlen($place_name) > 0) {
|
||||||
|
$res['name'] = $place_name;
|
||||||
|
} else {
|
||||||
|
$res['name'] = 'Geopoint';
|
||||||
|
}
|
||||||
|
|
||||||
|
$post->setGeo(json_encode($res));
|
||||||
|
$post->setGeo_Lat($latitude);
|
||||||
|
$post->setGeo_Lon($longitude);
|
||||||
|
}
|
||||||
|
|
||||||
if($should_be_suggested)
|
if($should_be_suggested)
|
||||||
$post->setSuggested(1);
|
$post->setSuggested(1);
|
||||||
|
|
||||||
|
@ -1129,6 +1174,52 @@ final class Wall extends VKAPIRequestHandler
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getNearby(int $owner_id, int $post_id)
|
||||||
|
{
|
||||||
|
$this->requireUser();
|
||||||
|
|
||||||
|
$post = (new PostsRepo)->getPostById($owner_id, $post_id);
|
||||||
|
if(!$post || $post->isDeleted())
|
||||||
|
$this->fail(100, "One of the parameters specified was missing or invalid: post_id is undefined");
|
||||||
|
|
||||||
|
if(!$post->canBeViewedBy($this->getUser()))
|
||||||
|
$this->fail(15, "Access denied");
|
||||||
|
|
||||||
|
$lat = $post->getLat();
|
||||||
|
$lon = $post->getLon();
|
||||||
|
|
||||||
|
if(!$lat || !$lon)
|
||||||
|
$this->fail(-97, "Post doesn't contains geo");
|
||||||
|
|
||||||
|
$query = file_get_contents(__DIR__ . "/../../Web/Models/sql/get-nearest-posts.tsql");
|
||||||
|
$_posts = \Chandler\Database\DatabaseConnection::i()->getContext()->query($query, $lat, $lon, $post->getId())->fetchAll();
|
||||||
|
$posts = [];
|
||||||
|
|
||||||
|
foreach($_posts as $post) {
|
||||||
|
$distance = $post["distance"];
|
||||||
|
$post = (new PostsRepo)->get($post["id"]);
|
||||||
|
if (!$post || $post->isDeleted() || !$post->canBeViewedBy($this->getUser())) continue;
|
||||||
|
|
||||||
|
$owner = $post->getOwner();
|
||||||
|
$preview = mb_substr($post->getText(), 0, 50) . (strlen($post->getText()) > 50 ? "..." : "");
|
||||||
|
$posts[] = [
|
||||||
|
"message" => strlen($preview) > 0 ? $preview : "(нет текста)",
|
||||||
|
"url" => "/wall" . $post->getPrettyId(),
|
||||||
|
"created" => $post->getPublicationTime()->html(),
|
||||||
|
"owner" => [
|
||||||
|
"domain" => $owner->getURL(),
|
||||||
|
"photo_50" => $owner->getAvatarURL(),
|
||||||
|
"name" => $owner->getCanonicalName(),
|
||||||
|
"verified" => $owner->isVerified(),
|
||||||
|
],
|
||||||
|
"geo" => $post->getGeo(),
|
||||||
|
"distance" => $distance
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $posts;
|
||||||
|
}
|
||||||
|
|
||||||
private function getApiPhoto($attachment) {
|
private function getApiPhoto($attachment) {
|
||||||
return [
|
return [
|
||||||
"type" => "photo",
|
"type" => "photo",
|
||||||
|
|
|
@ -456,5 +456,30 @@ class Post extends Postable
|
||||||
return $item;
|
return $item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getGeo(): ?object
|
||||||
|
{
|
||||||
|
if (!$this->getRecord()->geo) return NULL;
|
||||||
|
|
||||||
|
return (object) json_decode($this->getRecord()->geo, true, JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLat(): ?float
|
||||||
|
{
|
||||||
|
return (float) $this->getRecord()->geo_lat ?? NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLon(): ?float
|
||||||
|
{
|
||||||
|
return (float) $this->getRecord()->geo_lon ?? NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVkApiGeo(): object
|
||||||
|
{
|
||||||
|
return (object) [
|
||||||
|
'type' => 'point',
|
||||||
|
'coordinates' => $this->getLat() . ',' . $this->getLon(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
use Traits\TRichText;
|
use Traits\TRichText;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use openvk\Web\Themes\{Themepack, Themepacks};
|
||||||
use openvk\Web\Util\DateTime;
|
use openvk\Web\Util\DateTime;
|
||||||
use openvk\Web\Models\RowModel;
|
use openvk\Web\Models\RowModel;
|
||||||
use openvk\Web\Models\Entities\{Photo, Message, Correspondence, Gift, Audio};
|
use openvk\Web\Models\Entities\{Photo, Message, Correspondence, Gift, Audio};
|
||||||
use openvk\Web\Models\Repositories\{Applications, Bans, Comments, Notes, Posts, Users, Clubs, Albums, Gifts, Notifications, Videos, Photos};
|
use openvk\Web\Models\Repositories\{Applications, Bans, Comments, Notes, Posts, Users, Clubs, Albums, Gifts, Notifications, Videos, Photos};
|
||||||
use openvk\Web\Models\Exceptions\InvalidUserNameException;
|
use openvk\Web\Models\Exceptions\InvalidUserNameException;
|
||||||
use Nette\Database\Table\ActiveRow;
|
use Nette\Database\Table\ActiveRow;
|
||||||
use Chandler\Database\DatabaseConnection;
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
@ -511,7 +511,7 @@ class User extends RowModel
|
||||||
else if($user->getId() === $this->getId())
|
else if($user->getId() === $this->getId())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if($permission != "messages.write" && !$this->canBeViewedBy($user))
|
if(/*$permission != "messages.write" && */!$this->canBeViewedBy($user, true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
switch($permStatus) {
|
switch($permStatus) {
|
||||||
|
@ -1228,6 +1228,11 @@ class User extends RowModel
|
||||||
return (bool) $this->getRecord()->activated;
|
return (bool) $this->getRecord()->activated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isAdmin(): bool
|
||||||
|
{
|
||||||
|
return $this->getChandlerUser()->can("access")->model("admin")->whichBelongsTo(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
function isDead(): bool
|
function isDead(): bool
|
||||||
{
|
{
|
||||||
return $this->onlineStatus() == 2;
|
return $this->onlineStatus() == 2;
|
||||||
|
@ -1289,17 +1294,21 @@ class User extends RowModel
|
||||||
return $this->getRecord()->profile_type;
|
return $this->getRecord()->profile_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
function canBeViewedBy(?User $user = NULL): bool
|
function canBeViewedBy(?User $user = NULL, bool $blacklist_check = true): bool
|
||||||
{
|
{
|
||||||
if(!is_null($user)) {
|
if(!is_null($user)) {
|
||||||
if($this->getId() == $user->getId()) {
|
if($this->getId() == $user->getId()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($user->getChandlerUser()->can("access")->model("admin")->whichBelongsTo(NULL)) {
|
if($user->isAdmin() && !(OPENVK_ROOT_CONF['openvk']['preferences']['blacklists']['applyToAdmins'] ?? true)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($blacklist_check && ($this->isBlacklistedBy($user) || $user->isBlacklistedBy($this))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if($this->getProfileType() == 0) {
|
if($this->getProfileType() == 0) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1409,6 +1418,20 @@ class User extends RowModel
|
||||||
case 'real_id':
|
case 'real_id':
|
||||||
$res->real_id = $this->getRealId();
|
$res->real_id = $this->getRealId();
|
||||||
break;
|
break;
|
||||||
|
case "blacklisted_by_me":
|
||||||
|
if(!$user) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$res->blacklisted_by_me = (int)$this->isBlacklistedBy($user);
|
||||||
|
break;
|
||||||
|
case "blacklisted":
|
||||||
|
if(!$user) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$res->blacklisted = (int)$user->isBlacklistedBy($this);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1486,6 +1509,76 @@ class User extends RowModel
|
||||||
return DatabaseConnection::i()->getContext()->table("ignored_sources")->where("owner", $this->getId())->count();
|
return DatabaseConnection::i()->getContext()->table("ignored_sources")->where("owner", $this->getId())->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isBlacklistedBy(?User $user = NULL): bool
|
||||||
|
{
|
||||||
|
if(!$user)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$ctx = DatabaseConnection::i()->getContext();
|
||||||
|
$data = [
|
||||||
|
"author" => $user->getId(),
|
||||||
|
"target" => $this->getRealId(),
|
||||||
|
];
|
||||||
|
|
||||||
|
$sub = $ctx->table("blacklist_relations")->where($data);
|
||||||
|
return $sub->count() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addToBlacklist(?User $user)
|
||||||
|
{
|
||||||
|
DatabaseConnection::i()->getContext()->table("blacklist_relations")->insert([
|
||||||
|
"author" => $this->getRealId(),
|
||||||
|
"target" => $user->getRealId(),
|
||||||
|
"created" => time(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
DatabaseConnection::i()->getContext()->table("subscriptions")->where([
|
||||||
|
"follower" => $user->getId(),
|
||||||
|
"model" => static::class,
|
||||||
|
"target" => $this->getId(),
|
||||||
|
])->delete();
|
||||||
|
|
||||||
|
DatabaseConnection::i()->getContext()->table("subscriptions")->where([
|
||||||
|
"follower" => $this->getId(),
|
||||||
|
"model" => static::class,
|
||||||
|
"target" => $user->getId(),
|
||||||
|
])->delete();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFromBlacklist(?User $user): bool
|
||||||
|
{
|
||||||
|
DatabaseConnection::i()->getContext()->table("blacklist_relations")->where([
|
||||||
|
"author" => $this->getRealId(),
|
||||||
|
"target" => $user->getRealId(),
|
||||||
|
])->delete();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBlacklist(int $offset = 0, int $limit = 10)
|
||||||
|
{
|
||||||
|
$sources = DatabaseConnection::i()->getContext()->table("blacklist_relations")->where("author", $this->getId())->limit($limit, $offset)->order('created ASC');
|
||||||
|
$output_array = [];
|
||||||
|
|
||||||
|
foreach($sources as $source) {
|
||||||
|
$entity_id = (int)$source->target ;
|
||||||
|
$entity = (new Users)->get($entity_id);
|
||||||
|
if(!$entity)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$output_array[] = $entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output_array;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBlacklistSize()
|
||||||
|
{
|
||||||
|
return DatabaseConnection::i()->getContext()->table("blacklist_relations")->where("author", $this->getId())->count();
|
||||||
|
}
|
||||||
|
|
||||||
use Traits\TBackDrops;
|
use Traits\TBackDrops;
|
||||||
use Traits\TSubscribable;
|
use Traits\TSubscribable;
|
||||||
use Traits\TAudioStatuses;
|
use Traits\TAudioStatuses;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
11
Web/Models/sql/get-nearest-posts.tsql
Normal file
11
Web/Models/sql/get-nearest-posts.tsql
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
SELECT *,
|
||||||
|
SQRT(
|
||||||
|
POW(69.1 * (? - geo_lat), 2) +
|
||||||
|
POW(69.1 * (? - geo_lon) * COS(RADIANS(geo_lat)), 2)
|
||||||
|
) AS distance
|
||||||
|
FROM posts
|
||||||
|
WHERE id <> ?
|
||||||
|
AND FROM_UNIXTIME(created) >= DATE_SUB(NOW(), INTERVAL 1 MONTH)
|
||||||
|
HAVING distance < 1 AND distance IS NOT NULL
|
||||||
|
ORDER BY distance
|
||||||
|
LIMIT 25;
|
|
@ -119,7 +119,7 @@ final class GroupPresenter extends OpenVKPresenter
|
||||||
$this->template->paginatorConf = (object) [
|
$this->template->paginatorConf = (object) [
|
||||||
"count" => $this->template->count,
|
"count" => $this->template->count,
|
||||||
"page" => $this->queryParam("p") ?? 1,
|
"page" => $this->queryParam("p") ?? 1,
|
||||||
"amount" => NULL,
|
"amount" => 10,
|
||||||
"perPage" => OPENVK_DEFAULT_PER_PAGE,
|
"perPage" => OPENVK_DEFAULT_PER_PAGE,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ final class PhotosPresenter extends OpenVKPresenter
|
||||||
if(!$user) $this->notFound();
|
if(!$user) $this->notFound();
|
||||||
if (!$user->getPrivacyPermission('photos.read', $this->user->identity ?? NULL))
|
if (!$user->getPrivacyPermission('photos.read', $this->user->identity ?? NULL))
|
||||||
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment"));
|
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment"));
|
||||||
|
|
||||||
$this->template->albums = $this->albums->getUserAlbums($user, (int)($this->queryParam("p") ?? 1));
|
$this->template->albums = $this->albums->getUserAlbums($user, (int)($this->queryParam("p") ?? 1));
|
||||||
$this->template->count = $this->albums->getUserAlbumsCount($user);
|
$this->template->count = $this->albums->getUserAlbumsCount($user);
|
||||||
$this->template->owner = $user;
|
$this->template->owner = $user;
|
||||||
|
@ -161,8 +162,10 @@ final class PhotosPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
$photo = $this->photos->getByOwnerAndVID($ownerId, $photoId);
|
$photo = $this->photos->getByOwnerAndVID($ownerId, $photoId);
|
||||||
if(!$photo || $photo->isDeleted()) $this->notFound();
|
if(!$photo || $photo->isDeleted()) $this->notFound();
|
||||||
|
|
||||||
if(!$photo->canBeViewedBy($this->user->identity))
|
if(!$photo->canBeViewedBy($this->user->identity))
|
||||||
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment"));
|
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment"));
|
||||||
|
|
||||||
if(!is_null($this->queryParam("from"))) {
|
if(!is_null($this->queryParam("from"))) {
|
||||||
if(preg_match("%^album([0-9]++)$%", $this->queryParam("from"), $matches) === 1) {
|
if(preg_match("%^album([0-9]++)$%", $this->queryParam("from"), $matches) === 1) {
|
||||||
$album = $this->albums->get((int) $matches[1]);
|
$album = $this->albums->get((int) $matches[1]);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -29,10 +29,22 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
function renderView(int $id): void
|
function renderView(int $id): void
|
||||||
{
|
{
|
||||||
$user = $this->users->get($id);
|
$user = $this->users->get($id);
|
||||||
|
|
||||||
if(!$user || $user->isDeleted() || !$user->canBeViewedBy($this->user->identity)) {
|
if(!$user || $user->isDeleted() || !$user->canBeViewedBy($this->user->identity)) {
|
||||||
if(!is_null($user) && $user->isDeactivated()) {
|
if(!is_null($user) && $user->isDeactivated()) {
|
||||||
$this->template->_template = "User/deactivated.xml";
|
$this->template->_template = "User/deactivated.xml";
|
||||||
|
|
||||||
|
$this->template->user = $user;
|
||||||
|
} else if($this->user->identity->isBlacklistedBy($user)) {
|
||||||
|
$this->template->_template = "User/blacklisted.xml";
|
||||||
|
|
||||||
|
$this->template->blacklist_status = $user->isBlacklistedBy($this->user->identity);
|
||||||
|
$this->template->ignore_status = $user->isIgnoredBy($this->user->identity);
|
||||||
|
$this->template->user = $user;
|
||||||
|
} else if($user->isBlacklistedBy($this->user->identity)) {
|
||||||
|
$this->template->_template = "User/blacklisted_pov.xml";
|
||||||
|
|
||||||
|
$this->template->ignore_status = $user->isIgnoredBy($this->user->identity);
|
||||||
$this->template->user = $user;
|
$this->template->user = $user;
|
||||||
} else if(!is_null($user) && !$user->canBeViewedBy($this->user->identity)) {
|
} else if(!is_null($user) && !$user->canBeViewedBy($this->user->identity)) {
|
||||||
$this->template->_template = "User/private.xml";
|
$this->template->_template = "User/private.xml";
|
||||||
|
@ -57,6 +69,7 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
if($id !== $this->user->id) {
|
if($id !== $this->user->id) {
|
||||||
$this->template->ignore_status = $user->isIgnoredBy($this->user->identity);
|
$this->template->ignore_status = $user->isIgnoredBy($this->user->identity);
|
||||||
|
$this->template->blacklist_status = $user->isBlacklistedBy($this->user->identity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,7 +591,7 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
$this->flash("succ", tr("changes_saved"), tr("changes_saved_comment"));
|
$this->flash("succ", tr("changes_saved"), tr("changes_saved_comment"));
|
||||||
}
|
}
|
||||||
$this->template->mode = in_array($this->queryParam("act"), [
|
$this->template->mode = in_array($this->queryParam("act"), [
|
||||||
"main", "security", "privacy", "finance", "finance.top-up", "interface"
|
"main", "security", "privacy", "finance", "finance.top-up", "interface", "blacklist"
|
||||||
]) ? $this->queryParam("act")
|
]) ? $this->queryParam("act")
|
||||||
: "main";
|
: "main";
|
||||||
|
|
||||||
|
@ -591,6 +604,19 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
$this->template->qrCodeType = substr($qrCode[0], 5);
|
$this->template->qrCodeType = substr($qrCode[0], 5);
|
||||||
$this->template->qrCodeData = $qrCode[1];
|
$this->template->qrCodeData = $qrCode[1];
|
||||||
|
} else if($this->template->mode === "blacklist") {
|
||||||
|
$page = (int)($this->queryParam('p') ?? 1);
|
||||||
|
$count = 10;
|
||||||
|
$offset = ($page - 1) * $count;
|
||||||
|
|
||||||
|
$this->template->blSize = $this->user->identity->getBlacklistSize();
|
||||||
|
$this->template->blItems = $this->user->identity->getBlacklist($offset, $count);
|
||||||
|
$this->template->paginatorConf = (object) [
|
||||||
|
"count" => $this->template->blSize,
|
||||||
|
"page" => $page,
|
||||||
|
"amount" => sizeof($this->template->blItems),
|
||||||
|
"perPage" => OPENVK_DEFAULT_PER_PAGE,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->template->user = $user;
|
$this->template->user = $user;
|
||||||
|
|
|
@ -309,6 +309,19 @@ final class WallPresenter extends OpenVKPresenter
|
||||||
$this->flashFail("err", tr("failed_to_publish_post"), "Poll format invalid");
|
$this->flashFail("err", tr("failed_to_publish_post"), "Poll format invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$geo = NULL;
|
||||||
|
|
||||||
|
if (!is_null($this->postParam("geo")) && $this->postParam("geo") != "") {
|
||||||
|
$geo = json_decode($this->postParam("geo"), true, JSON_UNESCAPED_UNICODE);
|
||||||
|
if($geo["lat"] && $geo["lng"] && $geo["name"]) {
|
||||||
|
$latitude = number_format((float) $geo["lat"], 8, ".", '');
|
||||||
|
$longitude = number_format((float) $geo["lng"], 8, ".", '');
|
||||||
|
if($latitude > 90 || $latitude < -90 || $longitude > 180 || $longitude < -180) {
|
||||||
|
$this->flashFail("err", tr("error"), "Invalid latitude or longitude");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(empty($this->postParam("text")) && sizeof($horizontal_attachments) < 1 && sizeof($vertical_attachments) < 1 && !$poll)
|
if(empty($this->postParam("text")) && sizeof($horizontal_attachments) < 1 && sizeof($vertical_attachments) < 1 && !$poll)
|
||||||
$this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_empty_or_too_big"));
|
$this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_empty_or_too_big"));
|
||||||
|
|
||||||
|
@ -332,6 +345,11 @@ final class WallPresenter extends OpenVKPresenter
|
||||||
if($should_be_suggested)
|
if($should_be_suggested)
|
||||||
$post->setSuggested(1);
|
$post->setSuggested(1);
|
||||||
|
|
||||||
|
if ($geo) {
|
||||||
|
$post->setGeo(json_encode($geo));
|
||||||
|
$post->setGeo_Lat($latitude);
|
||||||
|
$post->setGeo_Lon($longitude);
|
||||||
|
}
|
||||||
$post->save();
|
$post->save();
|
||||||
} catch (\LengthException $ex) {
|
} catch (\LengthException $ex) {
|
||||||
$this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_too_big"));
|
$this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_too_big"));
|
||||||
|
|
|
@ -404,6 +404,11 @@
|
||||||
{script "js/al_feed.js"}
|
{script "js/al_feed.js"}
|
||||||
{/ifset}
|
{/ifset}
|
||||||
|
|
||||||
|
{script "js/node_modules/leaflet/dist/leaflet.js"}
|
||||||
|
{script "js/node_modules/leaflet-control-geocoder/dist/Control.Geocoder.js"}
|
||||||
|
{css "js/node_modules/leaflet/dist/leaflet.css"}
|
||||||
|
{css "js/node_modules/leaflet-control-geocoder/dist/Control.Geocoder.css"}
|
||||||
|
|
||||||
<script>bsdnHydrate();</script>
|
<script>bsdnHydrate();</script>
|
||||||
|
|
||||||
<script n:if="OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['enable']" async defer data-domain="{php echo OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['domain']}" src="{php echo OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['server']}js/plausible.js"></script>
|
<script n:if="OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['enable']" async defer data-domain="{php echo OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['domain']}" src="{php echo OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['server']}js/plausible.js"></script>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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"}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
{var $isFinance = $mode === 'finance'}
|
{var $isFinance = $mode === 'finance'}
|
||||||
{var $isFinanceTU = $mode === 'finance.top-up'}
|
{var $isFinanceTU = $mode === 'finance.top-up'}
|
||||||
{var $isInterface = $mode === 'interface'}
|
{var $isInterface = $mode === 'interface'}
|
||||||
|
{var $isBl = $mode === 'blacklist'}
|
||||||
|
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<div n:attr="id => ($isMain ? 'activetabs' : 'ki')" class="tab">
|
<div n:attr="id => ($isMain ? 'activetabs' : 'ki')" class="tab">
|
||||||
|
@ -24,6 +25,9 @@
|
||||||
<div n:attr="id => ($isPrivacy ? 'activetabs' : 'ki')" class="tab">
|
<div n:attr="id => ($isPrivacy ? 'activetabs' : 'ki')" class="tab">
|
||||||
<a n:attr="id => ($isPrivacy ? 'act_tab_a' : 'ki')" href="/settings?act=privacy">{_privacy}</a>
|
<a n:attr="id => ($isPrivacy ? 'act_tab_a' : 'ki')" href="/settings?act=privacy">{_privacy}</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div n:attr="id => ($isBl ? 'activetabs' : 'ki')" class="tab">
|
||||||
|
<a n:attr="id => ($isBl ? 'act_tab_a' : 'ki')" href="/settings?act=blacklist">{_blacklist}</a>
|
||||||
|
</div>
|
||||||
<div n:if="OPENVK_ROOT_CONF['openvk']['preferences']['commerce']" n:attr="id => (($isFinance || $isFinanceTU) ? 'activetabs' : 'ki')" class="tab">
|
<div n:if="OPENVK_ROOT_CONF['openvk']['preferences']['commerce']" n:attr="id => (($isFinance || $isFinanceTU) ? 'activetabs' : 'ki')" class="tab">
|
||||||
<a n:attr="id => (($isFinance || $isFinanceTU) ? 'act_tab_a' : 'ki')" href="/settings?act=finance">{_points}</a>
|
<a n:attr="id => (($isFinance || $isFinanceTU) ? 'act_tab_a' : 'ki')" href="/settings?act=finance">{_points}</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -713,7 +717,29 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
|
{elseif $isBl}
|
||||||
|
{if $blSize < 1}
|
||||||
|
{include "../components/error.xml", description => tr("bl_count_zero_desc")}
|
||||||
|
{else}
|
||||||
|
<h4 style="margin-bottom: 10px;">{tr("bl_count", $blSize)}.</h4>
|
||||||
|
<div class='entity_vertical_list mini m_mini scroll_container'>
|
||||||
|
<div n:foreach="$blItems as $item" class="entity_vertical_list_item scroll_node">
|
||||||
|
<div class="first_column">
|
||||||
|
<a href="{$item->getURL()}" class="avatar">
|
||||||
|
<img src='{$item->getAvatarURL()}'>
|
||||||
|
</a>
|
||||||
|
<div class="info">
|
||||||
|
<b class="noOverflow">
|
||||||
|
<a href="{$item->getURL()}">
|
||||||
|
{$item->getCanonicalName()}
|
||||||
|
</a>
|
||||||
|
</b>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{include "../components/paginator.xml", conf => $paginatorConf}
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,9 @@
|
||||||
</form>
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<a n:if="!$blacklist_status" id="_bl_toggler" data-name="{$user->getMorphedName('genitive', false)}" data-val="1" data-id="{$user->getRealId()}" class="profile_link" style="display:block;width:96%;">{_bl_add}</a>
|
||||||
|
{* 4 admins *}
|
||||||
|
<a n:if="$blacklist_status" id="_bl_toggler" data-val="0" data-id="{$user->getRealId()}" class="profile_link" style="display:block;width:96%;">{_bl_remove}</a>
|
||||||
<a class="profile_link" style="display:block;width:96%;" href="javascript:reportUser({$user->getId()})">{_report}</a>
|
<a class="profile_link" style="display:block;width:96%;" href="javascript:reportUser({$user->getId()})">{_report}</a>
|
||||||
<a n:if="!$user->isHideFromGlobalFeedEnabled()" class="profile_link" style="display:block;width:96%;" id="__ignoreSomeone" data-val='{!$ignore_status ? 1 : 0}' data-id="{$user->getId()}">
|
<a n:if="!$user->isHideFromGlobalFeedEnabled()" class="profile_link" style="display:block;width:96%;" id="__ignoreSomeone" data-val='{!$ignore_status ? 1 : 0}' data-id="{$user->getId()}">
|
||||||
{if !$ignore_status}{_ignore_user}{else}{_unignore_user}{/if}
|
{if !$ignore_status}{_ignore_user}{else}{_unignore_user}{/if}
|
||||||
|
|
42
Web/Presenters/templates/User/blacklisted.xml
Normal file
42
Web/Presenters/templates/User/blacklisted.xml
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
{extends "../@layout.xml"}
|
||||||
|
{block title}{$user->getCanonicalName()}{/block}
|
||||||
|
|
||||||
|
{block header}
|
||||||
|
{$user->getCanonicalName()}
|
||||||
|
<img n:if="$user->isVerified()"
|
||||||
|
class="name-checkmark"
|
||||||
|
src="/assets/packages/static/openvk/img/checkmark.png"
|
||||||
|
/>
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block content}
|
||||||
|
<div class="left_small_block">
|
||||||
|
<div>
|
||||||
|
<img src="{$user->getAvatarUrl('normal')}"
|
||||||
|
alt="{$user->getCanonicalName()}"
|
||||||
|
style="width: 100%; image-rendering: -webkit-optimize-contrast;" />
|
||||||
|
</div>
|
||||||
|
<div id="profile_links" n:if="isset($thisUser)">
|
||||||
|
<a class="profile_link" style="display:block;width:96%;" href="javascript:reportUser({$user->getId()})">{_report}</a>
|
||||||
|
<a n:if="!$blacklist_status" id="_bl_toggler" data-name="{$user->getMorphedName('genitive', false)}" data-val="1" data-id="{$user->getRealId()}" class="profile_link" style="display:block;width:96%;">{_bl_add}</a>
|
||||||
|
<a n:if="$blacklist_status" id="_bl_toggler" data-val="0" data-id="{$user->getRealId()}" class="profile_link" style="display:block;width:96%;">{_bl_remove}</a>
|
||||||
|
<a n:if="!$user->isHideFromGlobalFeedEnabled()" class="profile_link" style="display:block;width:96%;" id="__ignoreSomeone" data-val='{!$ignore_status ? 1 : 0}' data-id="{$user->getId()}">
|
||||||
|
{if !$ignore_status}{_ignore_user}{else}{_unignore_user}{/if}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="right_big_block">
|
||||||
|
<div class="page_info">
|
||||||
|
<div class="accountInfo clearFix">
|
||||||
|
<div class="profileName">
|
||||||
|
<h2>{$user->getFullName()}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="msg msg_yellow" style="width: 93%;margin-top: 10px;">
|
||||||
|
{var $m = $user->isFemale() ? "f" : "m"}
|
||||||
|
{tr("limited_access_to_page_$m", $user->getFirstName())}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/block}
|
40
Web/Presenters/templates/User/blacklisted_pov.xml
Normal file
40
Web/Presenters/templates/User/blacklisted_pov.xml
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
{extends "../@layout.xml"}
|
||||||
|
{block title}{$user->getCanonicalName()}{/block}
|
||||||
|
|
||||||
|
{block header}
|
||||||
|
{$user->getCanonicalName()}
|
||||||
|
<img n:if="$user->isVerified()"
|
||||||
|
class="name-checkmark"
|
||||||
|
src="/assets/packages/static/openvk/img/checkmark.png"
|
||||||
|
/>
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block content}
|
||||||
|
<div class="left_small_block">
|
||||||
|
<div>
|
||||||
|
<img src="{$user->getAvatarUrl('normal')}"
|
||||||
|
alt="{$user->getCanonicalName()}"
|
||||||
|
style="width: 100%; image-rendering: -webkit-optimize-contrast;" />
|
||||||
|
</div>
|
||||||
|
<div id="profile_links" n:if="isset($thisUser)">
|
||||||
|
<a n:if="!$blacklist_status" id="_bl_toggler" data-val="0" data-id="{$user->getRealId()}" class="profile_link" style="display:block;width:96%;">{_bl_remove}</a>
|
||||||
|
<a n:if="!$user->isHideFromGlobalFeedEnabled()" class="profile_link" style="display:block;width:96%;" id="__ignoreSomeone" data-val='{!$ignore_status ? 1 : 0}' data-id="{$user->getId()}">
|
||||||
|
{if !$ignore_status}{_ignore_user}{else}{_unignore_user}{/if}
|
||||||
|
</a>
|
||||||
|
<a class="profile_link" style="display:block;width:96%;" href="javascript:reportUser({$user->getId()})">{_report}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="right_big_block">
|
||||||
|
<div class="page_info">
|
||||||
|
<div class="accountInfo clearFix">
|
||||||
|
<div class="profileName">
|
||||||
|
<h2>{$user->getFullName()}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="msg msg_yellow" style="width: 93%;margin-top: 10px;">
|
||||||
|
{tr("you_blacklisted", $user->getMorphedName("genitive", false))}.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/block}
|
|
@ -41,6 +41,7 @@
|
||||||
<input type="submit" class="profile_link" value="{_friends_reject}" style="width: 194px;" />
|
<input type="submit" class="profile_link" value="{_friends_reject}" style="width: 194px;" />
|
||||||
</form>
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
|
<a id="_bl_toggler" data-name="{$user->getMorphedName('genitive', false)}" data-val="1" data-id="{$user->getRealId()}" class="profile_link" style="display:block;width:96%;">{_bl_add}</a>
|
||||||
<a class="profile_link" style="display:block;width:96%;" href="javascript:reportUser({$user->getId()})">{_report}</a>
|
<a class="profile_link" style="display:block;width:96%;" href="javascript:reportUser({$user->getId()})">{_report}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div n:class="postFeedWrapper, $thisUser->hasMicroblogEnabled() ? postFeedWrapperMicroblog">
|
<div n:class="postFeedWrapper, $thisUser->hasMicroblogEnabled() ? postFeedWrapperMicroblog">
|
||||||
{include "../components/textArea.xml", route => "/wall" . $thisUser->getId() . "/makePost", graffiti => true, polls => true, notes => true, hasSource => true}
|
{include "../components/textArea.xml", route => "/wall" . $thisUser->getId() . "/makePost", graffiti => true, polls => true, notes => true, hasSource => true, geo => true}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class='scroll_container'>
|
<div class='scroll_container'>
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div n:if="$canPost && $type == 'all'" class="content_subtitle">
|
<div n:if="$canPost && $type == 'all'" class="content_subtitle">
|
||||||
{include "../components/textArea.xml", route => "/wall$owner/makePost", graffiti => true, polls => true, notes => true, hasSource => true}
|
{include "../components/textArea.xml", route => "/wall$owner/makePost", graffiti => true, polls => true, notes => true, hasSource => true, geo => true}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content scroll_container">
|
<div class="content scroll_container">
|
||||||
|
|
|
@ -92,6 +92,14 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div n:if="$post->getGeo()" class="post-geo">
|
||||||
|
<a onclick="javascript:openGeo({$post->getGeo()}, {$post->getTargetWall()}, {$post->getVirtualId()})">
|
||||||
|
<svg class="map_svg_icon" width="13" height="12" viewBox="0 0 3.4395833 3.175">
|
||||||
|
<g><path d="M 1.7197917 0.0025838216 C 1.1850116 0.0049444593 0.72280427 0.4971031 0.71520182 1.0190592 C 0.70756921 1.5430869 1.7223755 3.1739665 1.7223755 3.1739665 C 1.7223755 3.1739665 2.7249195 1.5439189 2.7243815 0.99632161 C 2.7238745 0.48024825 2.2492929 0.00024648357 1.7197917 0.0025838216 z M 1.7197917 0.52606608 A 0.48526123 0.48526123 0 0 1 2.2050334 1.0113078 A 0.48526123 0.48526123 0 0 1 1.7197917 1.4965495 A 0.48526123 0.48526123 0 0 1 1.23455 1.0113078 A 0.48526123 0.48526123 0 0 1 1.7197917 0.52606608 z " /></g>
|
||||||
|
</svg>
|
||||||
|
{$post->getGeo()->name ?? tr("admin_open")}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<div n:if="$post->isAd()" style="color:grey;">
|
<div n:if="$post->isAd()" style="color:grey;">
|
||||||
<br/>
|
<br/>
|
||||||
! {_post_is_ad}
|
! {_post_is_ad}
|
||||||
|
|
|
@ -90,6 +90,14 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div n:if="$post->getGeo()" class="post-geo">
|
||||||
|
<div onclick="javascript:openGeo({$post->getGeo()}, {$post->getTargetWall()}, {$post->getVirtualId()})">
|
||||||
|
<svg class="map_svg_icon" width="13" height="12" viewBox="0 0 3.4395833 3.175">
|
||||||
|
<g><path d="M 1.7197917 0.0025838216 C 1.1850116 0.0049444593 0.72280427 0.4971031 0.71520182 1.0190592 C 0.70756921 1.5430869 1.7223755 3.1739665 1.7223755 3.1739665 C 1.7223755 3.1739665 2.7249195 1.5439189 2.7243815 0.99632161 C 2.7238745 0.48024825 2.2492929 0.00024648357 1.7197917 0.0025838216 z M 1.7197917 0.52606608 A 0.48526123 0.48526123 0 0 1 2.2050334 1.0113078 A 0.48526123 0.48526123 0 0 1 1.7197917 1.4965495 A 0.48526123 0.48526123 0 0 1 1.23455 1.0113078 A 0.48526123 0.48526123 0 0 1 1.7197917 0.52606608 z " /></g>
|
||||||
|
</svg>
|
||||||
|
<a>{$post->getGeo()->name ?? tr("admin_open")}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div n:if="$suggestion && $canBePinned" class="suggestionControls" style="margin-bottom: 7px;">
|
<div n:if="$suggestion && $canBePinned" class="suggestionControls" style="margin-bottom: 7px;">
|
||||||
<input type="button" class="button" id="publish_post" data-id="{$post->getId()}" value="{_publish_suggested}">
|
<input type="button" class="button" id="publish_post" data-id="{$post->getId()}" value="{_publish_suggested}">
|
||||||
<input type="button" class="button" id="decline_post" data-id="{$post->getId()}" value="{_decline_suggested}">
|
<input type="button" class="button" id="decline_post" data-id="{$post->getId()}" value="{_decline_suggested}">
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
<div class="post-has-poll">
|
<div class="post-has-poll">
|
||||||
{_poll}
|
{_poll}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="post-has-geo"></div>
|
||||||
<div class="post-source"></div>
|
<div class="post-source"></div>
|
||||||
|
|
||||||
<div n:if="$postOpts ?? true" class="post-opts">
|
<div n:if="$postOpts ?? true" class="post-opts">
|
||||||
|
@ -54,10 +55,12 @@
|
||||||
<input type="checkbox" name="as_group" /> {_comment_as_group}
|
<input type="checkbox" name="as_group" /> {_comment_as_group}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input type="hidden" name="horizontal_attachments" value="" autocomplete="off" />
|
<input type="hidden" name="horizontal_attachments" value="" autocomplete="off" />
|
||||||
<input type="hidden" name="vertical_attachments" value="" autocomplete="off" />
|
<input type="hidden" name="vertical_attachments" value="" autocomplete="off" />
|
||||||
<input type="hidden" name="poll" value="none" autocomplete="off" />
|
<input type="hidden" name="poll" value="none" autocomplete="off" />
|
||||||
<input type="hidden" id="source" name="source" value="none" autocomplete="off" />
|
<input type="hidden" id="source" name="source" value="none" autocomplete="off" />
|
||||||
|
<input type="hidden" name="geo" value="" autocomplete="off" />
|
||||||
<input type="hidden" name="type" value="1" autocomplete="off" />
|
<input type="hidden" name="type" value="1" autocomplete="off" />
|
||||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
<br/>
|
<br/>
|
||||||
|
@ -95,6 +98,10 @@
|
||||||
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/actions/office-chart-bar-stacked.png" />
|
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/actions/office-chart-bar-stacked.png" />
|
||||||
{_poll}
|
{_poll}
|
||||||
</a>
|
</a>
|
||||||
|
<a n:if="$geo ?? false" id="__geoAttacher">
|
||||||
|
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/apps/amarok.png" />
|
||||||
|
{_geo_place}
|
||||||
|
</a>
|
||||||
<a n:if="$hasSource ?? false" id='__sourceAttacher'>
|
<a n:if="$hasSource ?? false" id='__sourceAttacher'>
|
||||||
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/actions/insert-link.png" />
|
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/actions/insert-link.png" />
|
||||||
{_source}
|
{_source}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<div class="insertThere" id="postz"></div>
|
<div class="insertThere" id="postz"></div>
|
||||||
<div id="underHeader">
|
<div id="underHeader">
|
||||||
<div n:if="$canPost" class="content_subtitle">
|
<div n:if="$canPost" class="content_subtitle">
|
||||||
{include "../components/textArea.xml", route => "/wall$owner/makePost", graffiti => true, polls => true, notes => true, hasSource => true}
|
{include "../components/textArea.xml", route => "/wall$owner/makePost", graffiti => true, polls => true, notes => true, hasSource => true, geo => true}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content scroll_container">
|
<div class="content scroll_container">
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -851,6 +851,11 @@ h4 {
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.post-geo {
|
||||||
|
margin: 1px 0px;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.post-signature span {
|
.post-signature span {
|
||||||
color: grey;
|
color: grey;
|
||||||
}
|
}
|
||||||
|
@ -3597,6 +3602,11 @@ hr {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.entity_vertical_list.scroll_container {
|
||||||
|
height: unset;
|
||||||
|
overflow-y: unset;
|
||||||
|
}
|
||||||
|
|
||||||
.entity_vertical_list .entity_vertical_list_item {
|
.entity_vertical_list .entity_vertical_list_item {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@ -3611,6 +3621,15 @@ hr {
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.entity_vertical_list.m_mini .entity_vertical_list_item .first_column {
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entity_vertical_list.m_mini .entity_vertical_list_item .first_column .avatar img {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
.entity_vertical_list .entity_vertical_list_item .avatar {
|
.entity_vertical_list .entity_vertical_list_item .avatar {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
@ -3911,3 +3930,9 @@ hr {
|
||||||
top: 3px;
|
top: 3px;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.map_svg_icon {
|
||||||
|
display: inline-block;
|
||||||
|
margin-bottom: -2px;
|
||||||
|
fill: #7d7d7d;
|
||||||
|
}
|
||||||
|
|
|
@ -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>
|
||||||
`)
|
`)
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2587,3 +2587,283 @@ async function changeStatus() {
|
||||||
document.status_popup_form.submit.innerHTML = tr("send");
|
document.status_popup_form.submit.innerHTML = tr("send");
|
||||||
document.status_popup_form.submit.disabled = false;
|
document.status_popup_form.submit.disabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tplMapIcon = `<svg class="map_svg_icon" width="13" height="12" viewBox="0 0 3.4395833 3.175">
|
||||||
|
<g><path d="M 1.7197917 0.0025838216 C 1.1850116 0.0049444593 0.72280427 0.4971031 0.71520182 1.0190592 C 0.70756921 1.5430869 1.7223755 3.1739665 1.7223755 3.1739665 C 1.7223755 3.1739665 2.7249195 1.5439189 2.7243815 0.99632161 C 2.7238745 0.48024825 2.2492929 0.00024648357 1.7197917 0.0025838216 z M 1.7197917 0.52606608 A 0.48526123 0.48526123 0 0 1 2.2050334 1.0113078 A 0.48526123 0.48526123 0 0 1 1.7197917 1.4965495 A 0.48526123 0.48526123 0 0 1 1.23455 1.0113078 A 0.48526123 0.48526123 0 0 1 1.7197917 0.52606608 z " /></g>
|
||||||
|
</svg>`
|
||||||
|
|
||||||
|
u(document).on('click', "#__geoAttacher", async (e) => {
|
||||||
|
const form = u(e.target).closest('#write')
|
||||||
|
const buttons = form.find('.post-buttons')
|
||||||
|
|
||||||
|
let current_coords = [54.51331, 36.2732]
|
||||||
|
let currentMarker = null
|
||||||
|
const getCoords = async () => {
|
||||||
|
const pos = await new Promise((resolve, reject) => {
|
||||||
|
navigator.geolocation.getCurrentPosition((position) => {
|
||||||
|
resolve([position.coords.latitude, position.coords.longitude])
|
||||||
|
}, () => {
|
||||||
|
resolve([54.51331, 36.2732])
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enableHighAccuracy: true,
|
||||||
|
timeout: 5000,
|
||||||
|
maximumAge: 0,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
|
||||||
|
current_coords = await getCoords()
|
||||||
|
|
||||||
|
const geo_msg = new CMessageBox({
|
||||||
|
title: tr('attach_geotag'),
|
||||||
|
body: `<div id=\"osm-map\" style='height:75vh;'></div>`,
|
||||||
|
buttons: [tr('attach'), tr('cancel')],
|
||||||
|
callbacks: [() => {
|
||||||
|
if(!currentMarker) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const geo_name = $(`#geo-name`).html()
|
||||||
|
if(geo_name == '') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const marker = {
|
||||||
|
lat: currentMarker._latlng.lat,
|
||||||
|
lng: currentMarker._latlng.lng,
|
||||||
|
name: escapeHtml(geo_name)
|
||||||
|
}
|
||||||
|
buttons.find(`input[name='geo']`).nodes[0].value = JSON.stringify(marker)
|
||||||
|
buttons.find(`.post-has-geo`).html(`
|
||||||
|
${tplMapIcon}
|
||||||
|
<span>${escapeHtml(geo_name)}</span>
|
||||||
|
<div id="small_remove_button"></div>
|
||||||
|
`)
|
||||||
|
}, () => {}]
|
||||||
|
})
|
||||||
|
|
||||||
|
// by n1rwana
|
||||||
|
const markerLayers = L.layerGroup()
|
||||||
|
const map = L.map(u('#osm-map').nodes[0], {
|
||||||
|
center: current_coords,
|
||||||
|
zoom: 10,
|
||||||
|
attributionControl: false,
|
||||||
|
width: 800
|
||||||
|
})
|
||||||
|
markerLayers.addTo(map)
|
||||||
|
|
||||||
|
map.on('click', async (e) => {
|
||||||
|
const lat = e.latlng.lat
|
||||||
|
const lng = e.latlng.lng
|
||||||
|
|
||||||
|
if(currentMarker) map.removeLayer(currentMarker);
|
||||||
|
|
||||||
|
const marker_fetch_req = await fetch(`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=jsonv2`)
|
||||||
|
const marker_fetch = await marker_fetch_req.json()
|
||||||
|
|
||||||
|
markerLayers.clearLayers()
|
||||||
|
currentMarker = L.marker([lat, lng]).addTo(map)
|
||||||
|
|
||||||
|
let marker_name = marker_fetch && marker_fetch.display_name ? short_geo_name(marker_fetch.address) : tr('geotag')
|
||||||
|
const content = `<span id="geo-name">${marker_name}</span>`;
|
||||||
|
|
||||||
|
currentMarker.bindPopup(content).openPopup()
|
||||||
|
markerLayers.addLayer(currentMarker)
|
||||||
|
})
|
||||||
|
|
||||||
|
const geocoderControl = L.Control.geocoder({
|
||||||
|
defaultMarkGeocode: false,
|
||||||
|
}).addTo(map)
|
||||||
|
|
||||||
|
geocoderControl.on('markgeocode', function (e) {
|
||||||
|
console.log(e.geocode.properties)
|
||||||
|
const lat = e.geocode.properties.lat
|
||||||
|
const lng = e.geocode.properties.lon
|
||||||
|
const name = e.geocode.properties?.display_name ? short_geo_name(e.geocode.properties?.address) : tr('geotag')
|
||||||
|
|
||||||
|
if(currentMarker) map.removeLayer(currentMarker)
|
||||||
|
|
||||||
|
currentMarker = L.marker([lat, lng]).addTo(map)
|
||||||
|
currentMarker.bindPopup(`<span id="geo-name">${escapeHtml(name)}</span>`).openPopup()
|
||||||
|
|
||||||
|
marker = {
|
||||||
|
lat: lat,
|
||||||
|
lng: lng,
|
||||||
|
name: name
|
||||||
|
};
|
||||||
|
map.setView([lat, lng], 15);
|
||||||
|
})
|
||||||
|
|
||||||
|
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
|
||||||
|
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
|
||||||
|
}).addTo(map)
|
||||||
|
|
||||||
|
geo_msg.getNode().nodes[0].style = 'width:90%'
|
||||||
|
setTimeout(function(){ map.invalidateSize()}, 100)
|
||||||
|
})
|
||||||
|
|
||||||
|
u(document).on('click', '.post-has-geo #small_remove_button', (e) => {
|
||||||
|
const form = u(e.target).closest('#write')
|
||||||
|
const geo = form.find('.post-has-geo')
|
||||||
|
geo.remove()
|
||||||
|
form.find(`input[name='geo']`).nodes[0].value = ''
|
||||||
|
})
|
||||||
|
|
||||||
|
function openGeo(data, owner_id, virtual_id) {
|
||||||
|
MessageBox(tr("geotag"), "<div id=\"osm-map\"></div>", [tr("nearest_posts"), tr("close")], [async () => {
|
||||||
|
const posts = await OVKAPI.call('wall.getNearby', {owner_id: owner_id, post_id: virtual_id})
|
||||||
|
openNearPosts(posts)
|
||||||
|
}, Function.noop]);
|
||||||
|
|
||||||
|
let element = document.getElementById('osm-map');
|
||||||
|
element.style = 'height: 80vh;';
|
||||||
|
|
||||||
|
let map = L.map(element, {attributionControl: false});
|
||||||
|
let target = L.latLng(data.lat, data.lng);
|
||||||
|
map.setView(target, 15);
|
||||||
|
|
||||||
|
let marker = L.marker(target).addTo(map);
|
||||||
|
marker.bindPopup(escapeHtml(data.name ?? tr("geotag"))).openPopup();
|
||||||
|
|
||||||
|
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
|
||||||
|
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
$(".ovk-diag-cont").width('80%');
|
||||||
|
setTimeout(function(){ map.invalidateSize()}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tplPost(post) {
|
||||||
|
return `<a style="color: inherit; display: block; margin-bottom: 8px;" href="${post.url}">
|
||||||
|
<table border="0" style="font-size: 11px;" class="post">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td width="54" valign="top">
|
||||||
|
<a href="${post.owner.domain}">
|
||||||
|
<img src="${post.owner.photo_50}" width="50">
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td width="100%" valign="top">
|
||||||
|
<div class="post-author">
|
||||||
|
<a href="${post.owner.domain}"><b>${escapeHtml(post.owner.name)}</b></a>
|
||||||
|
${post.owner.verified ? `<img class="name-checkmark" src="/assets/packages/static/openvk/img/checkmark.png">` : ""}
|
||||||
|
<br>
|
||||||
|
<a href="${post.url}" class="date">
|
||||||
|
${post.created}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="post-content">
|
||||||
|
<div class="text">
|
||||||
|
${escapeHtml(post.message)}
|
||||||
|
</div>
|
||||||
|
<div style="padding: 4px;">
|
||||||
|
<div style="border-bottom: #ECECEC solid 1px;"></div>
|
||||||
|
<div style="cursor: pointer; padding: 4px;">
|
||||||
|
${tplMapIcon}
|
||||||
|
${escapeHtml(post.geo.name)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</a>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function openNearPosts(posts) {
|
||||||
|
if (posts.length > 0) {
|
||||||
|
let MsgTxt = "<div id=\"osm-map\"></div>";
|
||||||
|
MsgTxt += `<br /><br /><center style='color: grey;'>${tr('shown_last_nearest_posts', 25)}</center>`;
|
||||||
|
|
||||||
|
MessageBox(tr('nearest_posts'), MsgTxt, ["OK"], [Function.noop]);
|
||||||
|
|
||||||
|
let element = document.getElementById('osm-map');
|
||||||
|
element.style = 'height: 80vh;';
|
||||||
|
|
||||||
|
let markerLayers = L.layerGroup();
|
||||||
|
let map = L.map(element, {attributionControl: false});
|
||||||
|
|
||||||
|
markerLayers.addTo(map);
|
||||||
|
|
||||||
|
let markersBounds = [];
|
||||||
|
let coords = [];
|
||||||
|
|
||||||
|
posts.forEach((post) => {
|
||||||
|
if (coords.includes(`${post.geo.lat} ${post.geo.lng}`)) {
|
||||||
|
markerLayers.getLayers().forEach((marker) => {
|
||||||
|
if (marker.getLatLng().lat === post.geo.lat && marker.getLatLng().lng === post.geo.lng) {
|
||||||
|
let content = marker.getPopup()._content += tplPost(post);
|
||||||
|
if (!content.startsWith(`<div style="max-height: 300px; overflow-y: auto;">`))
|
||||||
|
content = `<div style="max-height: 300px; overflow-y: auto;">${content}`;
|
||||||
|
|
||||||
|
marker.getPopup().setContent(content);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let marker = L.marker(L.latLng(post.geo.lat, post.geo.lng)).addTo(map);
|
||||||
|
marker.bindPopup(tplPost(post));
|
||||||
|
markerLayers.addLayer(marker);
|
||||||
|
markersBounds.push(marker.getLatLng());
|
||||||
|
}
|
||||||
|
|
||||||
|
coords.push(`${post.geo.lat} ${post.geo.lng}`);
|
||||||
|
})
|
||||||
|
|
||||||
|
let bounds = L.latLngBounds(markersBounds);
|
||||||
|
map.fitBounds(bounds);
|
||||||
|
|
||||||
|
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
|
||||||
|
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
$(".ovk-diag-cont").width('80%');
|
||||||
|
setTimeout(function () {
|
||||||
|
map.invalidateSize()
|
||||||
|
}, 100);
|
||||||
|
} else {
|
||||||
|
MessageBox(tr('nearest_posts'), `<center style='color: grey;'>${tr('no_nearest_posts')}</center>`, ["OK"], [Function.noop]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u(document).on('click', '#_bl_toggler', async (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
const target = u(e.target)
|
||||||
|
const val = Number(target.attr('data-val'))
|
||||||
|
const id = Number(target.attr('data-id'))
|
||||||
|
const name = target.attr('data-name')
|
||||||
|
|
||||||
|
const fallback = (e) => {
|
||||||
|
fastError(e.message)
|
||||||
|
target.removeClass('lagged')
|
||||||
|
}
|
||||||
|
|
||||||
|
if(val == 1) {
|
||||||
|
const msg = new CMessageBox({
|
||||||
|
title: tr('addition_to_bl'),
|
||||||
|
body: `<span>${escapeHtml(tr('adding_to_bl_sure', name))}</span>`,
|
||||||
|
buttons: [tr('yes'), tr('no')],
|
||||||
|
callbacks: [async () => {
|
||||||
|
try {
|
||||||
|
target.addClass('lagged')
|
||||||
|
await window.OVKAPI.call('account.ban', {'owner_id': id})
|
||||||
|
window.router.route(location.href)
|
||||||
|
} catch(e) {
|
||||||
|
fallback(e)
|
||||||
|
}
|
||||||
|
}, () => Function.noop]
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
target.addClass('lagged')
|
||||||
|
await window.OVKAPI.call('account.unban', {'owner_id': id})
|
||||||
|
window.router.route(location.href)
|
||||||
|
} catch(e) {
|
||||||
|
fallback(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
"jquery": "^3.0.0",
|
"jquery": "^3.0.0",
|
||||||
"knockout": "^3.5.1",
|
"knockout": "^3.5.1",
|
||||||
"ky": "^0.19.0",
|
"ky": "^0.19.0",
|
||||||
|
"leaflet": "^1.9.4",
|
||||||
|
"leaflet-control-geocoder": "^2.4.0",
|
||||||
"literallycanvas": "^0.5.2",
|
"literallycanvas": "^0.5.2",
|
||||||
"monaco-editor": "^0.20.0",
|
"monaco-editor": "^0.20.0",
|
||||||
"msgpack-lite": "^0.1.26",
|
"msgpack-lite": "^0.1.26",
|
||||||
|
|
|
@ -164,6 +164,10 @@ window.router = new class {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(url.indexOf('#close') != -1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,6 +238,11 @@ window.router = new class {
|
||||||
}
|
}
|
||||||
|
|
||||||
u(document).on('click', 'a', async (e) => {
|
u(document).on('click', 'a', async (e) => {
|
||||||
|
if(e.defaultPrevented) {
|
||||||
|
console.log('AJAX | Skipping because default is prevented')
|
||||||
|
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 +298,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
|
||||||
|
|
|
@ -284,3 +284,30 @@ function collect_attachments_node(target)
|
||||||
})
|
})
|
||||||
vertical_input.nodes[0].value = vertical_array.join(',')
|
vertical_input.nodes[0].value = vertical_array.join(',')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function short_geo_name(address_osm)
|
||||||
|
{
|
||||||
|
let final_arr = []
|
||||||
|
if(address_osm.country) {
|
||||||
|
final_arr.push(address_osm.country)
|
||||||
|
}
|
||||||
|
if(address_osm.state) {
|
||||||
|
final_arr.push(address_osm.state)
|
||||||
|
}
|
||||||
|
if(address_osm.state_district) {
|
||||||
|
final_arr.push(address_osm.state_district)
|
||||||
|
}
|
||||||
|
if(address_osm.city) {
|
||||||
|
final_arr.push(address_osm.city)
|
||||||
|
} else if(address_osm.town) {
|
||||||
|
final_arr.push(address_osm.town)
|
||||||
|
}
|
||||||
|
if(address_osm.city_district) {
|
||||||
|
final_arr.push(address_osm.city_district)
|
||||||
|
}
|
||||||
|
if(address_osm.road) {
|
||||||
|
final_arr.push(address_osm.road)
|
||||||
|
}
|
||||||
|
|
||||||
|
return escapeHtml(final_arr.join(', '))
|
||||||
|
}
|
||||||
|
|
4
install/sqls/00051-posts-geo.sql
Normal file
4
install/sqls/00051-posts-geo.sql
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
ALTER TABLE `posts`
|
||||||
|
ADD `geo` LONGTEXT NULL DEFAULT NULL AFTER `deleted`,
|
||||||
|
ADD `geo_lat` DECIMAL(12, 8) NULL DEFAULT NULL AFTER `geo`,
|
||||||
|
ADD `geo_lon` DECIMAL(12, 8) NULL DEFAULT NULL AFTER `geo_lat`;
|
8
install/sqls/00052-blacklist.sql
Normal file
8
install/sqls/00052-blacklist.sql
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
CREATE TABLE `blacklist_relations` (
|
||||||
|
`index` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`author` BIGINT UNSIGNED NOT NULL,
|
||||||
|
`target` BIGINT UNSIGNED NOT NULL,
|
||||||
|
`created` BIGINT UNSIGNED NOT NULL,
|
||||||
|
PRIMARY KEY (`index`)
|
||||||
|
) ENGINE = InnoDB;
|
||||||
|
ALTER TABLE `blacklist_relations` ADD INDEX(`author`, `target`);
|
|
@ -240,6 +240,7 @@
|
||||||
"detach" = "Detach";
|
"detach" = "Detach";
|
||||||
"attach_photo" = "Attach photo";
|
"attach_photo" = "Attach photo";
|
||||||
"attach_video" = "Attach video";
|
"attach_video" = "Attach video";
|
||||||
|
"attach_geotag" = "Attach geotag";
|
||||||
"draw_graffiti" = "Draw graffiti";
|
"draw_graffiti" = "Draw graffiti";
|
||||||
"no_posts_abstract" = "Nobody wrote anything here... So far.";
|
"no_posts_abstract" = "Nobody wrote anything here... So far.";
|
||||||
"attach_no_longer_available" = "This attachment is no longer available.";
|
"attach_no_longer_available" = "This attachment is no longer available.";
|
||||||
|
@ -281,6 +282,15 @@
|
||||||
"liked_by_x_people_other" = "Liked by $1 users";
|
"liked_by_x_people_other" = "Liked by $1 users";
|
||||||
"liked_by_x_people_zero" = "Nobody liked";
|
"liked_by_x_people_zero" = "Nobody liked";
|
||||||
|
|
||||||
|
"geo_place" = "Place";
|
||||||
|
"geotag" = "Geotag";
|
||||||
|
"nearest_posts" = "Nearest posts";
|
||||||
|
"Latitude" = "Latitude";
|
||||||
|
"longitude" = "Longitude";
|
||||||
|
"name_of_the_place" = "Place's name";
|
||||||
|
"no_nearest_posts" = "No nearby posts";
|
||||||
|
"shown_last_nearest_posts" = "Showing last $1 posts per month";
|
||||||
|
|
||||||
/* Friends */
|
/* Friends */
|
||||||
|
|
||||||
"friends" = "Friends";
|
"friends" = "Friends";
|
||||||
|
@ -1604,6 +1614,8 @@
|
||||||
"error_adding_source_long" = "Error adding source: link is too long.";
|
"error_adding_source_long" = "Error adding source: link is too long.";
|
||||||
"error_adding_source_sus" = "Error adding source: suspicious link.";
|
"error_adding_source_sus" = "Error adding source: suspicious link.";
|
||||||
"error_playlist_creating_too_small" = "Add at least one audio";
|
"error_playlist_creating_too_small" = "Add at least one audio";
|
||||||
|
"error_geolocation" = "Error while trying to pin geolocation";
|
||||||
|
"error_no_geotag" = "There is no geo-tag pinned in this post";
|
||||||
|
|
||||||
/* Admin actions */
|
/* Admin actions */
|
||||||
|
|
||||||
|
@ -1699,6 +1711,7 @@
|
||||||
"admin_commerce_disabled" = "Commerce has been disabled by the system administrator";
|
"admin_commerce_disabled" = "Commerce has been disabled by the system administrator";
|
||||||
"admin_commerce_disabled_desc" = "The voucher and gift settings will be saved, but will have no effect.";
|
"admin_commerce_disabled_desc" = "The voucher and gift settings will be saved, but will have no effect.";
|
||||||
|
|
||||||
|
"admin_privacy_warning" = "Be careful with this information";
|
||||||
"admin_longpool_broken" = "Longpool is broken and will not work!";
|
"admin_longpool_broken" = "Longpool is broken and will not work!";
|
||||||
"admin_longpool_broken_desc" = "Make sure file at the path <code>$1</code> exist and have correct rights and ownership.";
|
"admin_longpool_broken_desc" = "Make sure file at the path <code>$1</code> exist and have correct rights and ownership.";
|
||||||
|
|
||||||
|
@ -1815,6 +1828,28 @@
|
||||||
"cookies_popup_content" = "Just like how kids love cookies, this website uses Cookies to identify your session and nothing more. Check <a href='/privacy'>our privacy policy</a> for more information.";
|
"cookies_popup_content" = "Just like how kids love cookies, this website uses Cookies to identify your session and nothing more. Check <a href='/privacy'>our privacy policy</a> for more information.";
|
||||||
"cookies_popup_agree" = "Accept";
|
"cookies_popup_agree" = "Accept";
|
||||||
|
|
||||||
|
/* Blacklist */
|
||||||
|
|
||||||
|
"blacklist" = "Blacklist";
|
||||||
|
"user_blacklisted_you" = "This user has blacklisted you.";
|
||||||
|
"user_blacklisted" = "$1 has been blacklisted";
|
||||||
|
"user_removed_from_the_blacklist" = "$1 has been removed from the blacklist.";
|
||||||
|
|
||||||
|
"adding_to_bl_sure" = "You sure you want to blacklist $1?";
|
||||||
|
|
||||||
|
"bl_count_zero_desc" = "There are no users on your blacklist yet.";
|
||||||
|
"bl_count_zero" = "There are no users on your blacklist";
|
||||||
|
"bl_count_one" = "You have one user on your blacklist";
|
||||||
|
"bl_count_few" = "You have $1 users on your blacklist";
|
||||||
|
"bl_count_many" = "You have $1 users on your blacklist";
|
||||||
|
"bl_count_other" = "You have $1 users on your blacklist";
|
||||||
|
|
||||||
|
"you_blacklisted" = "You blacklisted $1";
|
||||||
|
"bl_add" = "Add to blacklist";
|
||||||
|
"bl_remove" = "Remove from blacklist";
|
||||||
|
|
||||||
|
"addition_to_bl" = "Addition to blacklist";
|
||||||
|
|
||||||
/* Away */
|
/* Away */
|
||||||
|
|
||||||
"transition_is_blocked" = "Transition is blocked";
|
"transition_is_blocked" = "Transition is blocked";
|
||||||
|
|
|
@ -223,6 +223,7 @@
|
||||||
"detach" = "Открепить";
|
"detach" = "Открепить";
|
||||||
"attach_photo" = "Прикрепить фото";
|
"attach_photo" = "Прикрепить фото";
|
||||||
"attach_video" = "Прикрепить видео";
|
"attach_video" = "Прикрепить видео";
|
||||||
|
"attach_geotag" = "Прикрепить геометку";
|
||||||
"draw_graffiti" = "Нарисовать граффити";
|
"draw_graffiti" = "Нарисовать граффити";
|
||||||
"no_posts_abstract" = "Здесь никто ничего не написал... Пока.";
|
"no_posts_abstract" = "Здесь никто ничего не написал... Пока.";
|
||||||
"attach_no_longer_available" = "Это вложение больше недоступно.";
|
"attach_no_longer_available" = "Это вложение больше недоступно.";
|
||||||
|
@ -260,6 +261,15 @@
|
||||||
"liked_by_x_people_other" = "Понравилось $1 людям";
|
"liked_by_x_people_other" = "Понравилось $1 людям";
|
||||||
"liked_by_x_people_zero" = "Никому не понравилось";
|
"liked_by_x_people_zero" = "Никому не понравилось";
|
||||||
|
|
||||||
|
"geo_place" = "Место";
|
||||||
|
"geotag" = "Геолокация";
|
||||||
|
"nearest_posts" = "Ближайшие посты";
|
||||||
|
"Latitude" = "Широта";
|
||||||
|
"longitude" = "Долгота";
|
||||||
|
"name_of_the_place" = "Название места";
|
||||||
|
"no_nearest_posts" = "Нет ближайших постов";
|
||||||
|
"shown_last_nearest_posts" = "Показаны последние $1 постов за месяц";
|
||||||
|
|
||||||
/* Friends */
|
/* Friends */
|
||||||
|
|
||||||
"friends" = "Друзья";
|
"friends" = "Друзья";
|
||||||
|
@ -1507,6 +1517,8 @@
|
||||||
"error_adding_source_long" = "Ошибка добавления источника: слишком длинная ссылка.";
|
"error_adding_source_long" = "Ошибка добавления источника: слишком длинная ссылка.";
|
||||||
"error_adding_source_sus" = "Ошибка добавления источника: гиперссылка заблокирована.";
|
"error_adding_source_sus" = "Ошибка добавления источника: гиперссылка заблокирована.";
|
||||||
"error_playlist_creating_too_small" = "Добавь хотя бы одну аудиозапись.";
|
"error_playlist_creating_too_small" = "Добавь хотя бы одну аудиозапись.";
|
||||||
|
"error_geolocation" = "Ошибка при прикреплении геометки";
|
||||||
|
"error_no_geotag" = "У поста не указана гео-метка";
|
||||||
|
|
||||||
/* Admin actions */
|
/* Admin actions */
|
||||||
|
|
||||||
|
@ -1591,8 +1603,11 @@
|
||||||
"admin_about_instance" = "Инстанция";
|
"admin_about_instance" = "Инстанция";
|
||||||
"admin_commerce_disabled" = "Коммерция отключена системным администратором";
|
"admin_commerce_disabled" = "Коммерция отключена системным администратором";
|
||||||
"admin_commerce_disabled_desc" = "Настройки ваучеров и подарков будут сохранены, но не будут оказывать никакого влияния.";
|
"admin_commerce_disabled_desc" = "Настройки ваучеров и подарков будут сохранены, но не будут оказывать никакого влияния.";
|
||||||
|
|
||||||
|
"admin_privacy_warning" = "Будьте осторожны с этой информацией";
|
||||||
"admin_longpool_broken" = "Longpool сломан!";
|
"admin_longpool_broken" = "Longpool сломан!";
|
||||||
"admin_longpool_broken_desc" = "Проверьте, существует ли файл по пути <code>$1</code> и выданы ли у него правильные права на запись.";
|
"admin_longpool_broken_desc" = "Проверьте, существует ли файл по пути <code>$1</code> и выданы ли у него правильные права на запись.";
|
||||||
|
|
||||||
"admin_banned_links" = "Заблокированные ссылки";
|
"admin_banned_links" = "Заблокированные ссылки";
|
||||||
"admin_banned_link" = "Ссылка";
|
"admin_banned_link" = "Ссылка";
|
||||||
"admin_banned_domain" = "Домен";
|
"admin_banned_domain" = "Домен";
|
||||||
|
@ -1690,6 +1705,7 @@
|
||||||
"edit_action" = "Изменить";
|
"edit_action" = "Изменить";
|
||||||
"transfer" = "Передать";
|
"transfer" = "Передать";
|
||||||
"close" = "Закрыть";
|
"close" = "Закрыть";
|
||||||
|
"success" = "Успех";
|
||||||
"warning" = "Внимание";
|
"warning" = "Внимание";
|
||||||
"question_confirm" = "Это действие нельзя отменить. Вы действительно уверены в том что хотите сделать?";
|
"question_confirm" = "Это действие нельзя отменить. Вы действительно уверены в том что хотите сделать?";
|
||||||
"confirm_m" = "Подтвердить";
|
"confirm_m" = "Подтвердить";
|
||||||
|
@ -1708,6 +1724,28 @@
|
||||||
"cookies_popup_content" = "Все дети любят печенье, поэтому этот веб-сайт использует Cookies для того, чтобы идентифицировать вашу сессию и ничего более. Ознакомьтесь с нашей <a href='/privacy'>политикой конфиденциальности</a> для получения дополнительной информации.";
|
"cookies_popup_content" = "Все дети любят печенье, поэтому этот веб-сайт использует Cookies для того, чтобы идентифицировать вашу сессию и ничего более. Ознакомьтесь с нашей <a href='/privacy'>политикой конфиденциальности</a> для получения дополнительной информации.";
|
||||||
"cookies_popup_agree" = "Согласен";
|
"cookies_popup_agree" = "Согласен";
|
||||||
|
|
||||||
|
/* Blacklist */
|
||||||
|
|
||||||
|
"blacklist" = "Чёрный список";
|
||||||
|
"user_blacklisted_you" = "Пользователь внёс Вас в чёрный список.";
|
||||||
|
"user_blacklisted" = "$1 занесён в чёрный список.";
|
||||||
|
"user_removed_from_the_blacklist" = "$1 удалён из чёрного списка.";
|
||||||
|
|
||||||
|
"adding_to_bl_sure" = "Вы уверены, что хотите внести $1 в чёрный список?";
|
||||||
|
|
||||||
|
"bl_count_zero_desc" = "В вашем чёрном списке ещё нет пользователей.";
|
||||||
|
"bl_count_zero" = "В вашем чёрном списке нет пользователей";
|
||||||
|
"bl_count_one" = "В вашем чёрном списке один пользователь";
|
||||||
|
"bl_count_few" = "В вашем чёрном списке $1 пользователя";
|
||||||
|
"bl_count_many" = "В вашем чёрном списке $1 пользователей";
|
||||||
|
"bl_count_other" = "В вашем чёрном списке $1 пользователей";
|
||||||
|
|
||||||
|
"you_blacklisted" = "Вы внесли $1 в чёрный список";
|
||||||
|
"bl_add" = "Добавить в чёрный список";
|
||||||
|
"bl_remove" = "Удалить из чёрного списка";
|
||||||
|
|
||||||
|
"addition_to_bl" = "Добавление в чёрный список";
|
||||||
|
|
||||||
/* Away */
|
/* Away */
|
||||||
|
|
||||||
"transition_is_blocked" = "Переход по ссылке заблокирован";
|
"transition_is_blocked" = "Переход по ссылке заблокирован";
|
||||||
|
|
|
@ -38,6 +38,9 @@ openvk:
|
||||||
maxViolations: 50
|
maxViolations: 50
|
||||||
maxViolationsAge: 120
|
maxViolationsAge: 120
|
||||||
autoban: true
|
autoban: true
|
||||||
|
blacklists:
|
||||||
|
limit: 100
|
||||||
|
applyToAdmins: true
|
||||||
registration:
|
registration:
|
||||||
enable: true
|
enable: true
|
||||||
disablingReason: ""
|
disablingReason: ""
|
||||||
|
|
Loading…
Reference in a new issue