Merge branch 'master' into blacklist

This commit is contained in:
n1rwana 2022-10-01 17:14:43 +03:00 committed by GitHub
commit 03ac5b6554
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 904 additions and 452 deletions

View file

@ -1,11 +1,8 @@
<?xml encoding="UTF-8"?> <?xml encoding="UTF-8"?>
<!ELEMENT latte (tags,filters,variables,functions)> <!ELEMENT latte (tags,filters,variables,functions)>
<!ATTLIST latte vendor #REQUIRED> <!ATTLIST latte vendor #REQUIRED>
<!ATTLIST latte version #REQUIRED> <!ATTLIST latte version #REQUIRED>
<!ELEMENT tags (tag)+> <!ELEMENT tags (tag)+>
<!ELEMENT tag (arguments)?> <!ELEMENT tag (arguments)?>
<!ATTLIST tag name CDATA #REQUIRED> <!ATTLIST tag name CDATA #REQUIRED>
<!ATTLIST tag type (PAIR|UNPAIRED|UNPAIRED_ATTR|ATTR_ONLY|AUTO_EMPTY) #REQUIRED> <!ATTLIST tag type (PAIR|UNPAIRED|UNPAIRED_ATTR|ATTR_ONLY|AUTO_EMPTY) #REQUIRED>
@ -13,32 +10,24 @@
<!ATTLIST tag arguments CDATA #IMPLIED> <!ATTLIST tag arguments CDATA #IMPLIED>
<!ATTLIST tag deprecatedMessage CDATA #IMPLIED> <!ATTLIST tag deprecatedMessage CDATA #IMPLIED>
<!ATTLIST tag multiLine (true|false) #IMPLIED> <!ATTLIST tag multiLine (true|false) #IMPLIED>
<!ELEMENT arguments (argument)+> <!ELEMENT arguments (argument)+>
<!ELEMENT argument EMPTY> <!ELEMENT argument EMPTY>
<!ATTLIST argument name #REQUIRED> <!ATTLIST argument name #REQUIRED>
<!ATTLIST argument types CDATA #REQUIRED> <!ATTLIST argument types CDATA #REQUIRED>
<!ATTLIST argument repeatable (true|false) #IMPLIED> <!ATTLIST argument repeatable (true|false) #IMPLIED>
<!ATTLIST argument required (true|false) #IMPLIED> <!ATTLIST argument required (true|false) #IMPLIED>
<!ATTLIST argument validType #IMPLIED> <!ATTLIST argument validType #IMPLIED>
<!ELEMENT filters (filter)+> <!ELEMENT filters (filter)+>
<!ELEMENT filter EMPTY> <!ELEMENT filter EMPTY>
<!ATTLIST filter name #REQUIRED> <!ATTLIST filter name #REQUIRED>
<!ATTLIST filter description CDATA #IMPLIED> <!ATTLIST filter description CDATA #IMPLIED>
<!ATTLIST filter arguments CDATA #IMPLIED> <!ATTLIST filter arguments CDATA #IMPLIED>
<!ATTLIST filter insertColons #IMPLIED> <!ATTLIST filter insertColons #IMPLIED>
<!ELEMENT variables (variable)+> <!ELEMENT variables (variable)+>
<!ELEMENT variable EMPTY> <!ELEMENT variable EMPTY>
<!ATTLIST variable name #REQUIRED> <!ATTLIST variable name #REQUIRED>
<!ATTLIST variable type CDATA #REQUIRED> <!ATTLIST variable type CDATA #REQUIRED>
<!ELEMENT functions (function)+> <!ELEMENT functions (function)+>
<!ELEMENT function EMPTY> <!ELEMENT function EMPTY>
<!ATTLIST function name #REQUIRED> <!ATTLIST function name #REQUIRED>
<!ATTLIST function arguments CDATA #REQUIRED> <!ATTLIST function arguments CDATA #REQUIRED>

View file

@ -133,15 +133,18 @@ final class Friends extends VKAPIRequestHandler
return $response; return $response;
} }
function getRequests(string $fields = "", int $offset = 0, int $count = 100): object function getRequests(string $fields = "", int $offset = 0, int $count = 100, int $extended = 0): object
{ {
if ($count >= 1000)
$this->fail(100, "One of the required parameters was not passed or is invalid.");
$this->requireUser(); $this->requireUser();
$i = 0; $i = 0;
$offset++; $offset++;
$followers = []; $followers = [];
foreach($this->getUser()->getFollowers() as $follower) { foreach($this->getUser()->getFollowers($offset, $count) as $follower) {
$followers[$i] = $follower->getId(); $followers[$i] = $follower->getId();
$i++; $i++;
} }
@ -149,8 +152,10 @@ final class Friends extends VKAPIRequestHandler
$response = $followers; $response = $followers;
$usersApi = new Users($this->getUser()); $usersApi = new Users($this->getUser());
if(!is_null($fields)) if($extended == 1)
$response = $usersApi->get(implode(',', $followers), $fields, 0, $count); # FIXME $response = $usersApi->get(implode(',', $followers), $fields, 0, $count);
else
$response = $usersApi->get(implode(',', $followers), "", 0, $count);
foreach($response as $user) foreach($response as $user)
$user->user_id = $user->id; $user->user_id = $user->id;

View file

@ -27,14 +27,23 @@ class NewMessageEvent implements ILPEmitable
if($peer === $userId) if($peer === $userId)
$peer = $msg->getRecipient()->getId(); $peer = $msg->getRecipient()->getId();
/*
* Source:
* https://github.com/danyadev/longpoll-doc
*/
return [ return [
4, # event type 4, # event type
$msg->getId(), # messageId
256, # checked for spam flag 256, # checked for spam flag
$peer, # TODO calculate peer correctly $peer, # TODO calculate peer correctly
$msg->getSendTime()->timestamp(), # creation time in unix $msg->getSendTime()->timestamp(), # creation time in unix
$msg->getText(), # text (formatted) $msg->getText(), # text (formatted)
[], # empty additional info
[], # empty attachments [], # empty attachments
$msg->getId() << 2, # id as random_id $msg->getId() << 2, # id as random_id
$peer, # conversation id
0 # not edited yet
]; ];
} }
} }

View file

@ -0,0 +1,34 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Entities;
use openvk\Web\Models\RowModel;
use openvk\Web\Models\Entities\{User, Club};
use openvk\Web\Models\Repositories\{Users, Clubs};
class Alias extends RowModel
{
protected $tableName = "aliases";
function getOwnerId(): int
{
return $this->getRecord()->owner_id;
}
function getType(): string
{
if ($this->getOwnerId() < 0)
return "club";
return "user";
}
function getUser(): ?User
{
return (new Users)->get($this->getOwnerId());
}
function getClub(): ?Club
{
return (new Clubs)->get($this->getOwnerId() * -1);
}
}

View file

@ -911,6 +911,10 @@ class User extends RowModel
$pClub = DatabaseConnection::i()->getContext()->table("groups")->where("shortcode", $code)->fetch(); $pClub = DatabaseConnection::i()->getContext()->table("groups")->where("shortcode", $code)->fetch();
if(!is_null($pClub)) if(!is_null($pClub))
return false; return false;
$pAlias = DatabaseConnection::i()->getContext()->table("aliases")->where("shortcode", $code)->fetch();
if(!is_null($pAlias))
return false;
} }
$this->stateChanges("shortcode", $code); $this->stateChanges("shortcode", $code);

View file

@ -0,0 +1,35 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Repositories;
use openvk\Web\Models\Entities\Alias;
use Nette\Database\Table\ActiveRow;
use Chandler\Database\DatabaseConnection as DB;
use openvk\Web\Models\Entities\{Club, User};
use openvk\Web\Models\Repositories\{Clubs, Users};
class Aliases
{
private $context;
private $aliases;
function __construct()
{
$this->context = DB::i()->getContext();
$this->aliases = $this->context->table("aliases");
}
private function toAlias(?ActiveRow $ar): ?Alias
{
return is_null($ar) ? NULL : new Alias($ar);
}
function get(int $id): ?Alias
{
return $this->toAlias($this->aliases->get($id));
}
function getByShortcode(string $shortcode): ?Alias
{
return $this->toAlias($this->aliases->where("shortcode", $shortcode)->fetch());
}
}

View file

@ -1,6 +1,7 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
namespace openvk\Web\Models\Repositories; namespace openvk\Web\Models\Repositories;
use openvk\Web\Models\Entities\Club; use openvk\Web\Models\Entities\Club;
use openvk\Web\Models\Repositories\Aliases;
use Nette\Database\Table\ActiveRow; use Nette\Database\Table\ActiveRow;
use Chandler\Database\DatabaseConnection; use Chandler\Database\DatabaseConnection;
@ -22,7 +23,17 @@ class Clubs
function getByShortURL(string $url): ?Club function getByShortURL(string $url): ?Club
{ {
return $this->toClub($this->clubs->where("shortcode", $url)->fetch()); $shortcode = $this->toClub($this->clubs->where("shortcode", $url)->fetch());
if ($shortcode)
return $shortcode;
$alias = (new Aliases)->getByShortcode($url);
if (!$alias) return NULL;
if ($alias->getType() !== "club") return NULL;
return $alias->getClub();
} }
function get(int $id): ?Club function get(int $id): ?Club
@ -45,6 +56,9 @@ class Clubs
function getPopularClubs(): \Traversable function getPopularClubs(): \Traversable
{ {
// TODO rewrite
/*
$query = "SELECT ROW_NUMBER() OVER (ORDER BY `subscriptions` DESC) as `place`, `target` as `id`, COUNT(`follower`) as `subscriptions` FROM `subscriptions` WHERE `model` = \"openvk\\\Web\\\Models\\\Entities\\\Club\" GROUP BY `target` ORDER BY `subscriptions` DESC, `id` LIMIT 30;"; $query = "SELECT ROW_NUMBER() OVER (ORDER BY `subscriptions` DESC) as `place`, `target` as `id`, COUNT(`follower`) as `subscriptions` FROM `subscriptions` WHERE `model` = \"openvk\\\Web\\\Models\\\Entities\\\Club\" GROUP BY `target` ORDER BY `subscriptions` DESC, `id` LIMIT 30;";
$entries = DatabaseConnection::i()->getConnection()->query($query); $entries = DatabaseConnection::i()->getConnection()->query($query);
@ -54,6 +68,7 @@ class Clubs
"club" => $this->get($entry["id"]), "club" => $this->get($entry["id"]),
"subscriptions" => $entry["subscriptions"], "subscriptions" => $entry["subscriptions"],
]; ];
*/
} }
use \Nette\SmartObject; use \Nette\SmartObject;

View file

@ -1,6 +1,7 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
namespace openvk\Web\Models\Repositories; namespace openvk\Web\Models\Repositories;
use openvk\Web\Models\Entities\User; use openvk\Web\Models\Entities\User;
use openvk\Web\Models\Repositories\Aliases;
use Nette\Database\Table\ActiveRow; use Nette\Database\Table\ActiveRow;
use Chandler\Database\DatabaseConnection; use Chandler\Database\DatabaseConnection;
use Chandler\Security\User as ChandlerUser; use Chandler\Security\User as ChandlerUser;
@ -9,11 +10,13 @@ class Users
{ {
private $context; private $context;
private $users; private $users;
private $aliases;
function __construct() function __construct()
{ {
$this->context = DatabaseConnection::i()->getContext(); $this->context = DatabaseConnection::i()->getContext();
$this->users = $this->context->table("profiles"); $this->users = $this->context->table("profiles");
$this->aliases = $this->context->table("aliases");
} }
private function toUser(?ActiveRow $ar): ?User private function toUser(?ActiveRow $ar): ?User
@ -28,7 +31,17 @@ class Users
function getByShortURL(string $url): ?User function getByShortURL(string $url): ?User
{ {
return $this->toUser($this->users->where("shortcode", $url)->fetch()); $shortcode = $this->toUser($this->users->where("shortcode", $url)->fetch());
if ($shortcode)
return $shortcode;
$alias = (new Aliases)->getByShortcode($url);
if (!$alias) return NULL;
if ($alias->getType() !== "user") return NULL;
return $alias->getUser();
} }
function getByChandlerUser(ChandlerUser $user): ?User function getByChandlerUser(ChandlerUser $user): ?User

View file

@ -64,7 +64,7 @@ final class AboutPresenter extends OpenVKPresenter
$this->template->usersStats = (new Users)->getStatistics(); $this->template->usersStats = (new Users)->getStatistics();
$this->template->clubsCount = (new Clubs)->getCount(); $this->template->clubsCount = (new Clubs)->getCount();
$this->template->postsCount = (new Posts)->getCount(); $this->template->postsCount = (new Posts)->getCount();
$this->template->popularClubs = iterator_to_array((new Clubs)->getPopularClubs()); $this->template->popularClubs = [];
$this->template->admins = iterator_to_array((new Users)->getInstanceAdmins()); $this->template->admins = iterator_to_array((new Users)->getInstanceAdmins());
} }

View file

@ -6,7 +6,7 @@ use openvk\Web\Models\Repositories\Applications;
final class AppsPresenter extends OpenVKPresenter final class AppsPresenter extends OpenVKPresenter
{ {
private $apps; private $apps;
protected $presenterName = "apps";
function __construct(Applications $apps) function __construct(Applications $apps)
{ {
$this->apps = $apps; $this->apps = $apps;

View file

@ -84,6 +84,9 @@ final class AuthPresenter extends OpenVKPresenter
if (strtotime($this->postParam("birthday")) > time()) if (strtotime($this->postParam("birthday")) > time())
$this->flashFail("err", tr("invalid_birth_date"), tr("invalid_birth_date_comment")); $this->flashFail("err", tr("invalid_birth_date"), tr("invalid_birth_date_comment"));
if (!$this->postParam("confirmation"))
$this->flashFail("err", tr("error"), tr("checkbox_in_registration_unchecked"));
try { try {
$user = new User; $user = new User;
$user->setFirst_Name($this->postParam("first_name")); $user->setFirst_Name($this->postParam("first_name"));

View file

@ -6,6 +6,7 @@ use openvk\Web\Models\Repositories\{Comments, Clubs};
final class CommentPresenter extends OpenVKPresenter final class CommentPresenter extends OpenVKPresenter
{ {
protected $presenterName = "comment";
private $models = [ private $models = [
"posts" => "openvk\\Web\\Models\\Repositories\\Posts", "posts" => "openvk\\Web\\Models\\Repositories\\Posts",
"photos" => "openvk\\Web\\Models\\Repositories\\Photos", "photos" => "openvk\\Web\\Models\\Repositories\\Photos",

View file

@ -7,6 +7,7 @@ final class GiftsPresenter extends OpenVKPresenter
{ {
private $gifts; private $gifts;
private $users; private $users;
protected $presenterName = "gifts";
function __construct(Gifts $gifts, Users $users) function __construct(Gifts $gifts, Users $users)
{ {

View file

@ -8,6 +8,7 @@ use Chandler\Security\Authenticator;
final class GroupPresenter extends OpenVKPresenter final class GroupPresenter extends OpenVKPresenter
{ {
private $clubs; private $clubs;
protected $presenterName = "group";
function __construct(Clubs $clubs) function __construct(Clubs $clubs)
{ {

View file

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace openvk\Web\Presenters;
final class MaintenancePresenter extends OpenVKPresenter
{
protected $presenterName = "maintenance";
function renderSection(string $name): void
{
if(!OPENVK_ROOT_CONF["openvk"]["preferences"]["maintenanceMode"][$name])
$this->flashFail("err", tr("error"), tr("forbidden"));
$this->template->name = [
"photos" => tr("my_photos"),
"videos" => tr("my_videos"),
"messenger" => tr("my_messages"),
"user" => tr("users"),
"group" => tr("my_groups"),
"comment" => tr("comments"),
"gifts" => tr("gifts"),
"apps" => tr("apps"),
"notes" => tr("my_notes"),
"notification" => tr("my_feedback"),
"support" => tr("menu_support"),
"topics" => tr("topics")
][$name] ?? $name;
}
function renderAll(): void
{
}
}

View file

@ -9,11 +9,13 @@ final class MessengerPresenter extends OpenVKPresenter
{ {
private $messages; private $messages;
private $signaler; private $signaler;
protected $presenterName = "messenger";
function __construct(Messages $messages) function __construct(Messages $messages)
{ {
$this->messages = $messages; $this->messages = $messages;
$this->signaler = SignalManager::i(); $this->signaler = SignalManager::i();
parent::__construct(); parent::__construct();
} }
@ -94,6 +96,13 @@ final class MessengerPresenter extends OpenVKPresenter
$legacy = $this->queryParam("version") < 3; $legacy = $this->queryParam("version") < 3;
$time = intval($this->queryParam("wait"));
if($time > 60)
$time = 60;
elseif($time == 0)
$time = 25; // default
$this->signaler->listen(function($event, $eId) use ($id) { $this->signaler->listen(function($event, $eId) use ($id) {
exit(json_encode([ exit(json_encode([
"ts" => time(), "ts" => time(),
@ -101,7 +110,7 @@ final class MessengerPresenter extends OpenVKPresenter
$event->getVKAPISummary($id), $event->getVKAPISummary($id),
], ],
])); ]));
}, $id); }, $id, $time);
} }
function renderApiGetMessages(int $sel, int $lastMsg): void function renderApiGetMessages(int $sel, int $lastMsg): void

View file

@ -6,6 +6,7 @@ use openvk\Web\Models\Entities\Note;
final class NotesPresenter extends OpenVKPresenter final class NotesPresenter extends OpenVKPresenter
{ {
private $notes; private $notes;
protected $presenterName = "notes";
function __construct(Notes $notes) function __construct(Notes $notes)
{ {

View file

@ -3,6 +3,8 @@ namespace openvk\Web\Presenters;
final class NotificationPresenter extends OpenVKPresenter final class NotificationPresenter extends OpenVKPresenter
{ {
protected $presenterName = "notification";
function renderFeed(): void function renderFeed(): void
{ {
$this->assertUserLoggedIn(); $this->assertUserLoggedIn();

View file

@ -17,6 +17,7 @@ abstract class OpenVKPresenter extends SimplePresenter
protected $deactivationTolerant = false; protected $deactivationTolerant = false;
protected $errorTemplate = "@error"; protected $errorTemplate = "@error";
protected $user = NULL; protected $user = NULL;
protected $presenterName;
private function calculateQueryString(array $data): string private function calculateQueryString(array $data): string
{ {
@ -202,6 +203,7 @@ abstract class OpenVKPresenter extends SimplePresenter
$userValidated = 0; $userValidated = 0;
$cacheTime = OPENVK_ROOT_CONF["openvk"]["preferences"]["nginxCacheTime"] ?? 0; $cacheTime = OPENVK_ROOT_CONF["openvk"]["preferences"]["nginxCacheTime"] ?? 0;
if(!is_null($user)) { if(!is_null($user)) {
$this->user = (object) []; $this->user = (object) [];
$this->user->raw = $user; $this->user->raw = $user;
@ -264,6 +266,16 @@ abstract class OpenVKPresenter extends SimplePresenter
header("X-Accel-Expires: $cacheTime"); header("X-Accel-Expires: $cacheTime");
setlocale(LC_TIME, ...(explode(";", tr("__locale")))); setlocale(LC_TIME, ...(explode(";", tr("__locale"))));
if (!OPENVK_ROOT_CONF["openvk"]["preferences"]["maintenanceMode"]["all"]) {
if (OPENVK_ROOT_CONF["openvk"]["preferences"]["maintenanceMode"][$this->presenterName]) {
$this->pass("openvk!Maintenance->section", $this->presenterName);
}
} else {
if ($this->presenterName != "maintenance") {
$this->redirect("/maintenances/");
}
}
parent::onStartup(); parent::onStartup();
} }

View file

@ -9,6 +9,7 @@ final class PhotosPresenter extends OpenVKPresenter
private $users; private $users;
private $photos; private $photos;
private $albums; private $albums;
protected $presenterName = "photos";
function __construct(Photos $photos, Albums $albums, Users $users) function __construct(Photos $photos, Albums $albums, Users $users)
{ {

View file

@ -11,6 +11,7 @@ final class SupportPresenter extends OpenVKPresenter
{ {
protected $banTolerant = true; protected $banTolerant = true;
protected $deactivationTolerant = true; protected $deactivationTolerant = true;
protected $presenterName = "support";
private $tickets; private $tickets;
private $comments; private $comments;
@ -155,11 +156,12 @@ final class SupportPresenter extends OpenVKPresenter
$this->notFound(); $this->notFound();
} else { } else {
if($ticket->getUserId() !== $this->user->id && $this->hasPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0)) if($ticket->getUserId() !== $this->user->id && $this->hasPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0))
$this->redirect("/support/tickets"); $_redirect = "/support/tickets";
else else
$this->redirect("/support"); $_redirect = "/support?act=list";
$ticket->delete(); $ticket->delete();
$this->redirect($_redirect);
} }
} }
} }

View file

@ -7,6 +7,7 @@ final class TopicsPresenter extends OpenVKPresenter
{ {
private $topics; private $topics;
private $clubs; private $clubs;
protected $presenterName = "topics";
function __construct(Topics $topics, Clubs $clubs) function __construct(Topics $topics, Clubs $clubs)
{ {

View file

@ -14,11 +14,11 @@ use Nette\Database\UniqueConstraintViolationException;
final class UserPresenter extends OpenVKPresenter final class UserPresenter extends OpenVKPresenter
{ {
public $deactivationTolerant = false;
protected $presenterName = "user";
private $users; private $users;
private $blacklists; private $blacklists;
public $deactivationTolerant = false;
function __construct(Users $users, Blacklists $blacklists) function __construct(Users $users, Blacklists $blacklists)
{ {
$this->users = $users; $this->users = $users;

View file

@ -8,6 +8,7 @@ final class VideosPresenter extends OpenVKPresenter
{ {
private $videos; private $videos;
private $users; private $users;
protected $presenterName = "videos";
function __construct(Videos $videos, Users $users) function __construct(Videos $videos, Users $users)
{ {

View file

@ -87,12 +87,15 @@
{captcha_template()|noescape} {captcha_template()|noescape}
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
</td> </td>
<td> <td>
<input type="hidden" name="hash" value="{$csrfToken}" /> <input type="hidden" name="hash" value="{$csrfToken}" />
<input type="checkbox" required="true" name="confirmation" /> {_checkbox_in_registration|noescape}
<br /><br />
<input type="submit" value="{_registration}" class="button" /> <input type="submit" value="{_registration}" class="button" />
<a href="/login">{_log_in}</a> <a href="/login">{_log_in}</a>
</td> </td>

View file

@ -0,0 +1,20 @@
{extends "../@layout.xml"}
{block title}
{_global_maintenance}
{/block}
{block header}
{_global_maintenance}
{/block}
{block content}
<div class="container_gray">
<center style="background: white;border: #DEDEDE solid 1px;">
<img src="/assets/packages/static/openvk/img/oof.apng" style="width: 20%;" />
<span style="color: #707070;margin: 10px 0;display: block;">
{_undergoing_global_maintenance}
</span>
</center>
</div>
{/block}

View file

@ -0,0 +1,20 @@
{extends "../@layout.xml"}
{block title}
{_section_maintenance}
{/block}
{block header}
{_section_maintenance}
{/block}
{block content}
<div class="container_gray">
<center style="background: white;border: #DEDEDE solid 1px;">
<img src="/assets/packages/static/openvk/img/oof.apng" style="width: 20%;" />
<span style="color: #707070;margin: 10px 0;display: block;">
{tr("undergoing_section_maintenance", $name)|noescape}
</span>
</center>
</div>
{/block}

View file

@ -53,7 +53,7 @@
<div n:attr="id => ($act === 'online' ? 'activetabs' : 'ki')" class="tab"> <div n:attr="id => ($act === 'online' ? 'activetabs' : 'ki')" class="tab">
<a n:attr="id => ($act === 'online' ? 'act_tab_a' : 'ki')" href="?act=online">{_online}</a> <a n:attr="id => ($act === 'online' ? 'act_tab_a' : 'ki')" href="?act=online">{_online}</a>
</div> </div>
<div n:attr="id => ($act === 'incoming' || $act === 'outcoming' ? 'activetabs' : 'ki')" class="tab"> <div n:if="!is_null($thisUser) && $user->getId() === $thisUser->getId()" n:attr="id => ($act === 'incoming' || $act === 'outcoming' ? 'activetabs' : 'ki')" class="tab">
<a n:attr="id => ($act === 'incoming' || $act === 'outcoming' ? 'act_tab_a' : 'ki')" href="?act=incoming">{_req}</a> <a n:attr="id => ($act === 'incoming' || $act === 'outcoming' ? 'act_tab_a' : 'ki')" href="?act=incoming">{_req}</a>
</div> </div>
{/block} {/block}

View file

@ -79,9 +79,9 @@
{/block} {/block}
{block actions} {block actions}
<a href="{$x->getURL()}" class="profile_link">{_check_community}</a>
{if $x->canBeModifiedBy($thisUser ?? NULL)} {if $x->canBeModifiedBy($thisUser ?? NULL)}
{var $clubPinned = $thisUser->isClubPinned($x)} {var $clubPinned = $thisUser->isClubPinned($x)}
<a href="{$x->getURL()}" class="profile_link">{_check_community}</a>
<a href="/groups_pin?club={$x->getId()}&hash={rawurlencode($csrfToken)}" class="profile_link" n:if="$clubPinned || $thisUser->getPinnedClubCount() <= 10" id="_pinGroup" data-group-name="{$x->getName()}" data-group-url="{$x->getUrl()}"> <a href="/groups_pin?club={$x->getId()}&hash={rawurlencode($csrfToken)}" class="profile_link" n:if="$clubPinned || $thisUser->getPinnedClubCount() <= 10" id="_pinGroup" data-group-name="{$x->getName()}" data-group-url="{$x->getUrl()}">
{if $clubPinned} {if $clubPinned}
{_remove_from_left_menu} {_remove_from_left_menu}
@ -89,6 +89,15 @@
{_add_to_left_menu} {_add_to_left_menu}
{/if} {/if}
</a> </a>
{/if}
{if $x->getSubscriptionStatus($thisUser) == false}
<form class="profile_link_form" action="/setSub/club" method="post">
<input type="hidden" name="act" value="add" />
<input type="hidden" name="id" value="{$x->getId()}" />
<input type="hidden" name="hash" value="{$csrfToken}" />
<input type="submit" class="profile_link" value="{_join_community}" />
</form>
{else}
<form class="profile_link_form" action="/setSub/club" method="post"> <form class="profile_link_form" action="/setSub/club" method="post">
<input type="hidden" name="act" value="rem" /> <input type="hidden" name="act" value="rem" />
<input type="hidden" name="id" value="{$x->getId()}" /> <input type="hidden" name="id" value="{$x->getId()}" />

View file

@ -45,4 +45,6 @@ services:
- openvk\Web\Models\Repositories\Applications - openvk\Web\Models\Repositories\Applications
- openvk\Web\Models\Repositories\ContentSearchRepository - openvk\Web\Models\Repositories\ContentSearchRepository
- openvk\Web\Models\Repositories\Blacklists - openvk\Web\Models\Repositories\Blacklists
- openvk\Web\Models\Repositories\Aliases
- openvk\Web\Models\Repositories\BannedLinks - openvk\Web\Models\Repositories\BannedLinks
- openvk\Web\Presenters\MaintenancePresenter

View file

@ -335,3 +335,7 @@ routes:
handler: "UnknownTextRouteStrategy->delegate" handler: "UnknownTextRouteStrategy->delegate"
placeholders: placeholders:
shortCode: "[a-z][a-z0-9\\@\\.\\_]{0,30}[a-z0-9]" shortCode: "[a-z][a-z0-9\\@\\.\\_]{0,30}[a-z0-9]"
- url: "/maintenance/{text}"
handler: "Maintenance->section"
- url: "/maintenances/"
handler: "Maintenance->all"

View file

@ -1,14 +1,13 @@
CREATE TABLE `links_banned` ( CREATE TABLE `links_banned` (
`id` bigint UNSIGNED NOT NULL, `id` bigint UNSIGNED NOT NULL,
`domain` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `domain` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_nopad_ci NOT NULL,
`regexp_rule` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `regexp_rule` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_nopad_ci NOT NULL,
`reason` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, `reason` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_nopad_ci,
`initiator` bigint UNSIGNED NOT NULL `initiator` bigint UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_nopad_ci;
ALTER TABLE `links_banned` ALTER TABLE `links_banned`
ADD PRIMARY KEY (`id`); ADD PRIMARY KEY (`id`);
ALTER TABLE `links_banned` ALTER TABLE `links_banned`
MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT; MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT;
COMMIT;

View file

@ -0,0 +1,11 @@
CREATE TABLE `aliases` (
`id` bigint UNSIGNED NOT NULL,
`owner_id` bigint NOT NULL,
`shortcode` varchar(36) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_nopad_ci;
ALTER TABLE `aliases`
ADD PRIMARY KEY (`id`);
ALTER TABLE `aliases`
MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT;

View file

@ -17,6 +17,8 @@
"password" = "Գաղտնաբառ"; "password" = "Գաղտնաբառ";
"registration" = "Գրանցում"; "registration" = "Գրանցում";
"forgot_password" = "Մոռացե՞լ եք գաղտնաբառը"; "forgot_password" = "Մոռացե՞լ եք գաղտնաբառը";
"checkbox_in_registration" = "Ես համաձայն եմ <a href='/privacy'>կոնֆիդենցիալության քաղաքականությանն</a> ու <a href='/about'>կայքի կանոնադրությանը</a>։";
"checkbox_in_registration_unchecked" = "Դուք պետք է համաձայնվեք պայմանների հետ նախքան գրանցվելը։";
"login_failed" = "Չհաջողվեց մուտք գործել"; "login_failed" = "Չհաջողվեց մուտք գործել";
"invalid_username_or_password" = "Սխալ օգտատիրոջ անուն կամ գաղտնաբառ։ Դուք կարող եք <a href='/restore'>վերականգնել ձեր գաղտնաբառը</a>։"; "invalid_username_or_password" = "Սխալ օգտատիրոջ անուն կամ գաղտնաբառ։ Դուք կարող եք <a href='/restore'>վերականգնել ձեր գաղտնաբառը</a>։";
@ -93,6 +95,9 @@
"years_many" = "$1 տարեկան"; "years_many" = "$1 տարեկան";
"years_other" = "$1 տարեկան"; "years_other" = "$1 տարեկան";
"show_my_birthday" = "Ցույց տալ ծննդյան օրը";
"show_only_month_and_day" = "Ցուցադրել միայն ամիսն ու օրը";
"relationship" = "Ընտանեկան դրություն"; "relationship" = "Ընտանեկան դրություն";
"relationship_0" = "Ընտրված չէ"; "relationship_0" = "Ընտրված չէ";
@ -144,8 +149,8 @@
"updated_at" = "Թարմացված է $1"; "updated_at" = "Թարմացված է $1";
"user_banned" = "Ցավո՛ք, մենք ստիպված <b>$1</b>-ի էջը կասեցրել ենք։"; "user_banned" = "Ցավո՛ք, մենք ստիպված կասեցրել ենք <b>$1</b>-ի էջը։";
"user_banned_comment" = "Մոդերատորի մեկնաբանությունը․ "; "user_banned_comment" = "Մոդերատորի մեկնաբանությունը․";
/* Wall */ /* Wall */
@ -154,6 +159,10 @@
"post_writes_m" = "գրել է"; "post_writes_m" = "գրել է";
"post_writes_f" = "գրել է"; "post_writes_f" = "գրել է";
"post_writes_g" = "հրապարակել են"; "post_writes_g" = "հրապարակել են";
"post_deact_m" = "ջնջել է էջը հետևյալ բառերով.";
"post_deact_f" = "ջնջել է էջը հետևյալ բառերով.";
"post_deact_silent_m" = "սուս ու փուս ջնջել է էջը։";
"post_deact_silent_f" = "սուս ու փուս ջնջել է էջը։";
"wall" = "Պատ"; "wall" = "Պատ";
"post" = "Գրություն"; "post" = "Գրություն";
"write" = "Գրել"; "write" = "Գրել";
@ -167,7 +176,7 @@
"comments_tip" = "Եղե՛ք առաջինը ով կթողնի իր կարծիքը։"; "comments_tip" = "Եղե՛ք առաջինը ով կթողնի իր կարծիքը։";
"your_comment" = "Ձեր մեկնաբանությունը"; "your_comment" = "Ձեր մեկնաբանությունը";
"shown" = "Ցուցադրված է"; "shown" = "Ցուցադրված է";
"x_out_of" = "$1 –ը ՝"; "x_out_of" = "$1ը";
"wall_zero" = "գրություն չկա"; "wall_zero" = "գրություն չկա";
"wall_one" = "մեկ գրություն"; "wall_one" = "մեկ գրություն";
"wall_few" = "$1 գրություն"; "wall_few" = "$1 գրություն";
@ -215,6 +224,8 @@
"incoming_req" = "Բաժանորդներ"; "incoming_req" = "Բաժանորդներ";
"outcoming_req" = "Հայցեր"; "outcoming_req" = "Հայցեր";
"req" = "Հայցեր"; "req" = "Հայցեր";
"friends_online" = "Ընկերները ցանցում";
"all_friends" = "Բոլոր ընկերները";
"req_zero" = "Ոչ մի հայտ չի գտնվել..."; "req_zero" = "Ոչ մի հայտ չի գտնվել...";
"req_one" = "Գտնվեց մեկ հայտ"; "req_one" = "Գտնվեց մեկ հայտ";
@ -246,6 +257,12 @@
"subscriptions_many" = "$1 բաժանորդագրություն"; "subscriptions_many" = "$1 բաժանորդագրություն";
"subscriptions_other" = "$1 բաժանորդագրություն"; "subscriptions_other" = "$1 բաժանորդագրություն";
"friends_list_online_zero" = "Դուք դեռ չունեք ցանցի մեջ գտնվող ընկերներ";
"friends_list_online_one" = "Ձեր $1 ընկերը ցանցի մեջ է";
"friends_list_online_few" = "Ձեր $1 ընկերները ցանցի մեջ են";
"friends_list_online_many" = "Ձեր $1 ընկերները ցանցի մեջ են";
"friends_list_online_other" = "Ձեր $1 ընկերները ցանցի մեջ են";
/* Group */ /* Group */
"name_group" = "Անվանում"; "name_group" = "Անվանում";
@ -364,6 +381,10 @@
"edit_note" = "Խմբագրել նշումը"; "edit_note" = "Խմբագրել նշումը";
"actions" = "Գործողություններ"; "actions" = "Գործողություններ";
"notes_start_screen" = "Նշումների շնորհիվ Դուք կարող եք կիսվել ընկերների հետ տարբեր իրադարձություններով, և իմանալ թե ինչ է կատարվում իրենց մոտ։"; "notes_start_screen" = "Նշումների շնորհիվ Դուք կարող եք կիսվել ընկերների հետ տարբեր իրադարձություններով, և իմանալ թե ինչ է կատարվում իրենց մոտ։";
"note_preview" = "Նախադիտում";
"note_preview_warn" = "Սա ընդամենը նախադիտում է";
"note_preview_warn_details" = "Պահպանելուց հետո նշումները կարող են այլ տեսք ունենալ։ Ու մեկ էլ, այդքան հաճախ նախադիտում մի արեք։";
"note_preview_empty_err" = "Ինչու՞ նախադիտել նշումը առանց վերնագրի կամ բովանդակության։";
"edited" = "Խմբագրված է"; "edited" = "Խմբագրված է";
@ -428,6 +449,7 @@
"avatar" = "Ավատար"; "avatar" = "Ավատար";
"privacy" = "Գաղտնիություն"; "privacy" = "Գաղտնիություն";
"interface" = "Արտաքին տեսք"; "interface" = "Արտաքին տեսք";
"security" = "Անվտանգություն";
"profile_picture" = "Էջի նկար"; "profile_picture" = "Էջի նկար";
@ -445,7 +467,7 @@
"arbitrary_avatars" = "Կամայական"; "arbitrary_avatars" = "Կամայական";
"cut" = "Կտրվածք"; "cut" = "Կտրվածք";
"round_avatars" = "Կլոր ավատար"; "round_avatars" = "Շրջանաձև";
"apply_style_for_this_device" = "Հաստատել տեսքը միայն այս սարքի համար"; "apply_style_for_this_device" = "Հաստատել տեսքը միայն այս սարքի համար";
@ -508,6 +530,33 @@
"email_change_confirm_message" = "Որպեսզի Ձեր փոփոխությունը կատարվի, հաստատե՛ք Ձեր նոր էլեկտրոնային հասցեն։ Այնտեղ մենք ուղարկել ենք հրահանգները։"; "email_change_confirm_message" = "Որպեսզի Ձեր փոփոխությունը կատարվի, հաստատե՛ք Ձեր նոր էլեկտրոնային հասցեն։ Այնտեղ մենք ուղարկել ենք հրահանգները։";
"profile_deactivate" = "Էջի հեռացում";
"profile_deactivate_button" = "Ջնջել էջը";
"profile_deactivate_header" = "Մենք ցավում ենք որ Դուք ցանկանում եք ջնջել ձեր էջը։ Դրա համար Դուք կարող եք նշել հեռացման պատճառը և Ձեր կարծիքը այդ առումով։ Մեզ համար կարևոր է Ձեր կարծիքը, որպեսզի դարձնենք կայքը ավելի լավը։";
"profile_deactivate_reason_header" = "Խնդրում ենք, նշել Ձեր էջի ջնջման պատճառները";
"profile_deactivate_reason_1" = "Ես ունեմ այլ էջ այս կայնքում";
"profile_deactivate_reason_1_text" = "Ես նոր էջ եմ սկսել ու ցանկանում եմ սկսել ամեն ինչ նորից";
"profile_deactivate_reason_2" = "Կայքն ինձնից շատ ժամանակ է խլում";
"profile_deactivate_reason_2_text" = "Թեկուզ այս կայքը լավն է, բայց ցավոք ինձնից ահագին ժամանակ է խլում։";
"profile_deactivate_reason_3" = "Կայքը բազմաթիվ անցանկանալի մատերիալներ է պարունակում";
"profile_deactivate_reason_3_text" = "Ես բազմաթիվ պոռնոգրաֆիա ու անօրինական կինոներ եմ գրել բոլ ա։ Հիմա հավես չկա։";
"profile_deactivate_reason_4" = "Ինձ անհանգստացնում է իմ տվյալների անվտանգությունը";
"profile_deactivate_reason_4_text" = "Ինձ հետևում են ու շատ վախենալու է ինձ այստեղ գտնվելը";
"profile_deactivate_reason_5" = "Իմ էջը չեն մեկնաբանում";
"profile_deactivate_reason_5_text" = "Ինձ այստեղ շան տեղ դնող չկա ու ես տխրում եմ։ Դուք կզղջաք որ ես հեռացա...";
"profile_deactivate_reason_6" = "Այլ պատճառ";
"profile_deactivated_msg" = "Ձեր էջը <b>ջնջված է</b>։<br/><br/>Եթե Դուք ուզենաք նորից օգտվել Ձեր էջով, կարող եք <a href='/settings/reactivate'>ապաակտիվացնել այն</a> մինչև $1:";
"profile_deactivated_status" = "Էջը ջնջված է";
"profile_deactivated_info" = "Օգտատիրոջ էջը հեռացվել է։<br/>Մանրամասն տեղեկատվությունը բացակայում է։";
"share_with_friends" = "Պատմել ընկերներին";
"end_all_sessions" = "Դուրս գալ բոլոր սեսսիաներից";
"end_all_sessions_description" = "Եթե ցանկանում եք դուրս գալ $1ից ամեն դեվայսից, սեղմե՛ք ներքևի կոճակը";
"end_all_sessions_done" = "Բոլոր սեսսիաները նետված են, ներառյալ բջջային հավելվածները";
/* Two-factor authentication */ /* Two-factor authentication */
"two_factor_authentication" = "Երկքայլ աուտենտիֆիկացիա"; "two_factor_authentication" = "Երկքայլ աուտենտիֆիկացիա";
@ -708,6 +757,75 @@
"users_gifts" = "Նվերներ"; "users_gifts" = "Նվերներ";
/* Apps */
"app" = "Հավելված";
"apps" = "Հավելվածներ";
"my_apps" = "Իմ հավելվածները";
"all_apps" = "Բոլոր հավելվածները";
"installed_apps" = "Տեղադրված հավելվածները";
"own_apps" = "Կառավարում";
"own_apps_alternate" = "Իմ այլ հավելվածները";
"app_play" = "միացնել";
"app_uninstall" = "անջատել";
"app_edit" = "խմբագրել";
"app_dev" = "Մշակող";
"create_app" = "Ստեղծել հավելված";
"edit_app" = "Խմբագրել հավելվածը";
"new_app" = "Նոր հավելված";
"app_news" = "Նորություններով նշում";
"app_state" = "Կարգավիճակ";
"app_enabled" = "Միացված է";
"app_creation_hint_url" = "URLում նշեք կոնկրետ հասցեն իր սխեմայով (https), պորտով (80) և անհրաժեշտ միացման կարգավորումներով։";
"app_creation_hint_iframe" = "Ձեր հավելվածը բացված է iframeով։";
"app_balance" = "Հավելվածի հաշվին կա <b>$1</b> ձայն։";
"app_users" = "Ձեր հավելվածով օգտվում է <b>$1</b> հոգի։";
"app_withdrawal_q" = "դուրս բերե՞լ";
"app_withdrawal" = "Միջոցների դուրս բերում";
"app_withdrawal_empty" = "Կներեք, դատարկությունը չհաջողվեց դուրս բերել։";
"app_withdrawal_created" = "$1 ձայնի դուրս բերման հայտը գրանցված է։ Սպասեք հաշվառմանը։";
"appjs_payment" = "Գնման վճարում";
"appjs_payment_intro" = "Դուք պատրաստվում եք հավելվածի գնումը վճարել";
"appjs_order_items" = "Գնման ցուցակ";
"appjs_payment_total" = "Վճարման ընդհանուր գին";
"appjs_payment_confirm" = "Վճարել";
"appjs_err_funds" = "Չհաջողվե՛ց վճարել գնումը անբավարար միջոցների համար։";
"appjs_wall_post" = "Հրապարակել գրությունտը";
"appjs_wall_post_desc" = "ցանկանում է Ձեր պատին գրություն թողնել";
"appjs_sperm_friends" = "ձեր ընկերներին";
"appjs_sperm_friends_desc" = "ավելացնել օգտատերերին որպես ընկերներ և կարդալ Ձեր գրությունները";
"appjs_sperm_wall" = "ձեր պատին";
"appjs_sperm_wall_desc" = "դիտել Ձեր լուրերը, կարդալ պատն ու թողել գրություններ";
"appjs_sperm_messages" = "ձեր նամակներին";
"appjs_sperm_messages_desc" = "կարդալ և գրել նամակներ Ձեր անունից";
"appjs_sperm_groups" = "ձեր հանրություններին";
"appjs_sperm_groups_desc" = "դիտել Ձեր խմբերի ցուցակն ու բաժանորդագրել դեպի այլ խմբեր";
"appjs_sperm_likes" = "լայքելու ֆունկցիոնալին";
"appjs_sperm_likes_desc" = "տեղադրել և հանել \"Դուր գալու\" ռեակցիաները ձայնագրություններից";
"appjs_sperm_request" = "Հասանելիության հարցում";
"appjs_sperm_requests" = "հասանելիություն է խնդրում";
"appjs_sperm_can" = "Հավելվածը կարող է";
"appjs_sperm_allow" = "Թույլատրել";
"appjs_sperm_disallow" = "Չթույլատրել";
"app_uninstalled" = "Հավելվածն անջատված է";
"app_uninstalled_desc" = "Այն Ձեր անունից էլ չի կարող կատարել գործողություններ։";
"app_err_not_found" = "Հավելվածը չի գտնվել";
"app_err_not_found_desc" = "Սխալ կամ անջատված իդենտիֆիկատոր։";
"app_err_forbidden_desc" = "Այս հավելվածը Ձերը չէ։";
"app_err_url" = "Սխալ հասցե";
"app_err_url_desc" = "Հավելվածի հասցեն չանցավ ստուգումը. համոզվե՛ք որ այն ճիշտ է գրված:";
"app_err_ava" = "Չհաջողվե՛ց վերբեռնել ավատարը:";
"app_err_ava_desc" = "Ավատարը չափազանց մեծ և ծուռ է. ընդհանուր բնույթի սխալ №$res.";
"app_err_note" = "Չհաջողվե՛ց ամրացնել նորությունների նիշքը";
"app_err_note_desc" = "Համոզվե՛ք որ հղումը ճիշտ է և պատկանում է Ձեզ։";
/* Support */ /* Support */
"support_opened" = "Բաց"; "support_opened" = "Բաց";
@ -767,7 +885,12 @@
"banned_alt" = "Օգտատերը արգելափակված է"; "banned_alt" = "Օգտատերը արգելափակված է";
"banned_1" = "Կներե՛ք, <b>$1</b>, բայց Դուք կասեցված եք։"; "banned_1" = "Կներե՛ք, <b>$1</b>, բայց Դուք կասեցված եք։";
"banned_2" = "Պատճառը հետևյալն է․ <b>$1</b>. Ափսոս, բայց մենք ստիպված Ձեզ հավերժ ենք կասեցրել;"; "banned_2" = "Պատճառը հետևյալն է․ <b>$1</b>. Ափսոս, բայց մենք ստիպված Ձեզ հավերժ ենք կասեցրել;";
"banned_perm" = "Ցավոք, մենք ստիպված արգելափակել ենք Ձեզ ընդմիշտ։";
"banned_until_time" = "Այս անգամ մենք ստիպված արգելափակել ենք Ձեզ մինչև <b>$1</b>";
"banned_3" = "Դուք դեռ կարող եք <a href=\"/support?act=new\">գրել նամակ աջակցության ծառայությանը</a>, եթե համարում եք որ դա սխալմունք է, կամ էլ կարող եք <a href=\"/logout?hash=$1\">դուրս գալ</a>։"; "banned_3" = "Դուք դեռ կարող եք <a href=\"/support?act=new\">գրել նամակ աջակցության ծառայությանը</a>, եթե համարում եք որ դա սխալմունք է, կամ էլ կարող եք <a href=\"/logout?hash=$1\">դուրս գալ</a>։";
"banned_unban_myself" = "Ապասառեցնել էջը";
"banned_unban_title" = "Ձեր հաշիվը ապասառեցված է։";
"banned_unban_description" = "Աշխատե՛ք այլևս չխախտել կանոնները։";
/* Registration confirm */ /* Registration confirm */
@ -996,6 +1119,17 @@
"admin_commerce_disabled" = "Կոմմերցիան անջատված է համակարգային ադմինիստրատորի կողմից"; "admin_commerce_disabled" = "Կոմմերցիան անջատված է համակարգային ադմինիստրատորի կողմից";
"admin_commerce_disabled_desc" = "Վաուչերների և նվերների կարգավորումները կպահպանվեն, բայց ոչ մի ազդեցություն չեն ունենա։"; "admin_commerce_disabled_desc" = "Վաուչերների և նվերների կարգավորումները կպահպանվեն, բայց ոչ մի ազդեցություն չեն ունենա։";
"admin_banned_links" = "Արգելափակված հղումներ";
"admin_banned_link" = "Հղում";
"admin_banned_domain" = "Դոմեն";
"admin_banned_link_description" = "Պրոտոկոլով (https://example.com/)";
"admin_banned_link_regexp" = "Ռեգուլյար արտահայտություն";
"admin_banned_link_regexp_description" = "Տեղադրվում է վերոնշյալ դոմենից հետո։ Մի լրացրե՛ք, եթե ցանկանում եք արգելափակել ամբողջ դոմենը";
"admin_banned_link_reason" = "Պատճառ";
"admin_banned_link_initiator" = "Նախաձեռնող";
"admin_banned_link_not_specified" = "Հղումը նշված չէ";
"admin_banned_link_not_found" = "Հղումը չի գտնվել";
/* Paginator (deprecated) */ /* Paginator (deprecated) */
"paginator_back" = "Հետ"; "paginator_back" = "Հետ";
@ -1059,3 +1193,21 @@
"cookies_popup_content" = "Cookie բառը անգլերենից նշանակում է թխվածքաբլիթ, իսկ թխվածքաբլիթը համեղ է։ Մեր կայքը չի ուտում թխվածք, բայց օգտագործում է այն ուղղակի սեսսիան կողմնորոշելու համար։ Ավելի մանրամասն կարող եք ծանոթանալ մեր <a href='/privacy'>գաղտնիության քաղաքականությանը</a> հավելյալ ինֆորմացիայի համար։"; "cookies_popup_content" = "Cookie բառը անգլերենից նշանակում է թխվածքաբլիթ, իսկ թխվածքաբլիթը համեղ է։ Մեր կայքը չի ուտում թխվածք, բայց օգտագործում է այն ուղղակի սեսսիան կողմնորոշելու համար։ Ավելի մանրամասն կարող եք ծանոթանալ մեր <a href='/privacy'>գաղտնիության քաղաքականությանը</a> հավելյալ ինֆորմացիայի համար։";
"cookies_popup_agree" = "Համաձայն եմ"; "cookies_popup_agree" = "Համաձայն եմ";
/* Away */
"url_is_banned" = "Անցումն անհնար է";
"url_is_banned_comment" = "Ադմինիստրացիան <b>$1</b> խորհուրդ չի տալից անցնել այս հղումով։";
"url_is_banned_comment_r" = "Ադմինիստրացիան <b>$1</b> խորհուրդ չի տալից անցնել այս հղումով։<br><br>Պատճառը: <b>$2</b>";
"url_is_banned_default_reason" = "Հղումը դեպի կայք կարող է ստեղծված լինել շորթողներից ՝ օգտատերերին խաբելու և խարդախության նպատակներով, շահույթ ստանալու համար։";
"url_is_banned_title" = "Հղում դեպի կասկածելի կայք";
"url_is_banned_proceed" = "Անցնել հղումով";
/* Maintenance */
"global_maintenance" = "Տեխնիկական աշխատանքներ";
"section_maintenance" = "Բաժինը անհասանելի է";
"undergoing_global_maintenance" = "Ցավոք սրտի, հիմա հոսքը փակված է տեխնիկական աշխատանքներ անցկացնելու համար։ Մենք արդեն աշխատում ենք խնդիրները շտկելու ուղղությամբ։ Խնդրում ենք այցելել մի քիչ ուշ։";
"undergoing_section_maintenance" = "Ցավոք սրտի, <b>$1</b> բաժինը ժամանակավորապես անհասանելի է։ Մենք արդեն աշխատում ենք խնդիրները շտկելու ուղղությամբ։ Խնդրում ենք այցելել մի քիչ ուշ։";
"topics" = "Թեմաներ";

View file

@ -1156,3 +1156,12 @@
"url_is_banned_default_reason" = "The link you are trying to open may lead you to a site that was created for the purpose of deceiving users with the intention of gaining profit."; "url_is_banned_default_reason" = "The link you are trying to open may lead you to a site that was created for the purpose of deceiving users with the intention of gaining profit.";
"url_is_banned_title" = "Link to a suspicious site"; "url_is_banned_title" = "Link to a suspicious site";
"url_is_banned_proceed" = "Follow the link"; "url_is_banned_proceed" = "Follow the link";
/* Maintenance */
"global_maintenance" = "Undergoing maintenance";
"section_maintenance" = "The section is not available";
"undergoing_global_maintenance" = "Unfortunately, the instance is now closed for technical work. We are already working on troubleshooting. Please try to come back later.";
"undergoing_section_maintenance" = "Unfortunately, the <b>$1</b> section is temporarily unavailable. We are already working on troubleshooting. Please try to come back later.";
"topics" = "Topics";

View file

@ -13,7 +13,7 @@ list:
flag: "ua" flag: "ua"
name: "Ukrainian" name: "Ukrainian"
native_name: "Україньска" native_name: "Україньска"
author: "Andrej Lenťaj, Maxim Hrabovi (dechioyo) and Kirill (mbsoft)" author: "Yaroslav Bjelograd, Andrej Lenťaj, Maxim Hrabovi (dechioyo) and Kirill (mbsoft)"
- code: "by" - code: "by"
flag: "by" flag: "by"
name: "Belarussian" name: "Belarussian"

View file

@ -15,6 +15,8 @@
"password" = "Пароль"; "password" = "Пароль";
"registration" = "Регистрация"; "registration" = "Регистрация";
"forgot_password" = "Забыли пароль?"; "forgot_password" = "Забыли пароль?";
"checkbox_in_registration" = "Я согласен с <a href='/privacy'>политикой конфиденциальности</a> и <a href='/about'>правилами сайта</a>";
"checkbox_in_registration_unchecked" = "Вы должны согласиться с политикой конфиденциальности и правилами, чтобы зарегистрироваться.";
"login_failed" = "Не удалось войти"; "login_failed" = "Не удалось войти";
"invalid_username_or_password" = "Неверное имя пользователя или пароль. <a href='/restore'>Забыли пароль?</a>"; "invalid_username_or_password" = "Неверное имя пользователя или пароль. <a href='/restore'>Забыли пароль?</a>";
@ -990,7 +992,7 @@
"changes_saved_comment" = "Новые данные появятся на вашей странице"; "changes_saved_comment" = "Новые данные появятся на вашей странице";
"photo_saved" = "Фотография сохранена"; "photo_saved" = "Фотография сохранена";
"photo_saved_comment" = "Новое изображние профиля появится у вас на странице"; "photo_saved_comment" = "Новое изображение профиля появится у вас на странице";
"shared_succ" = "Запись появится на вашей стене. Нажмите на уведомление, чтобы перейти к своей стене."; "shared_succ" = "Запись появится на вашей стене. Нажмите на уведомление, чтобы перейти к своей стене.";
@ -1216,3 +1218,12 @@
"url_is_banned_default_reason" = "Ссылка, по которой вы попытались перейти, может вести на сайт, который был создан с целью обмана пользователей и получения за счёт этого прибыли."; "url_is_banned_default_reason" = "Ссылка, по которой вы попытались перейти, может вести на сайт, который был создан с целью обмана пользователей и получения за счёт этого прибыли.";
"url_is_banned_title" = "Ссылка на подозрительный сайт"; "url_is_banned_title" = "Ссылка на подозрительный сайт";
"url_is_banned_proceed" = "Перейти по ссылке"; "url_is_banned_proceed" = "Перейти по ссылке";
/* Maintenance */
"global_maintenance" = "Технические работы";
"section_maintenance" = "Раздел недоступен";
"undergoing_global_maintenance" = "К сожалению, сейчас инстанс закрыт на технические работы. Мы уже работаем над устранением неисправностей. Пожалуйста, попробуйте зайти позже.";
"undergoing_section_maintenance" = "К сожалению, раздел <b>$1</b> временно недоступен. Мы уже работаем над устранением неисправностей. Пожалуйста, попробуйте зайти позже.";
"topics" = "Темы";

View file

@ -15,6 +15,8 @@
"password" = "Пароль"; "password" = "Пароль";
"registration" = "Реєстрація"; "registration" = "Реєстрація";
"forgot_password" = "Забули пароль?"; "forgot_password" = "Забули пароль?";
"checkbox_in_registration" = "Я згоден з <a href='/privacy'>політикою конфіденційності</a> і <a href='/about'>правилами сайту</a>";
"checkbox_in_registration_unchecked" = "Ви повинні погодитися з політикою конфіденційності та правилами, щоб зареєструватися.";
"login_failed" = "Не вдалося увійти"; "login_failed" = "Не вдалося увійти";
"invalid_username_or_password" = "Неправильне ім'я користувача або пароль. <a href='/restore'>Забули пароль?</a>"; "invalid_username_or_password" = "Неправильне ім'я користувача або пароль. <a href='/restore'>Забули пароль?</a>";
@ -210,6 +212,7 @@
/* Friends */ /* Friends */
"friends" = "Друзі";
"followers" = "Підписники"; "followers" = "Підписники";
"follower" = "Підписник"; "follower" = "Підписник";
"friends_add" = "Додати в друзі"; "friends_add" = "Додати в друзі";
@ -218,10 +221,11 @@
"friends_accept" = "Прийняти заявку"; "friends_accept" = "Прийняти заявку";
"send_message" = "Відправити повідомлення"; "send_message" = "Відправити повідомлення";
"incoming_req" = "Підписники"; "incoming_req" = "Підписники";
"outcoming_req" = "Вихідні";
"req" = "Заявки";
"outcoming_req" = "Заявки"; "outcoming_req" = "Заявки";
"friends_online" = "Друзі онлайн"; "friends_online" = "Друзі онлайн";
"all_friends" = "Усі друзі"; "all_friends" = "Усі друзі";
"req" = "Заявки";
"req_zero" = "Не знайдено жодної заявки..."; "req_zero" = "Не знайдено жодної заявки...";
"req_one" = "Знайдена $1 заявка"; "req_one" = "Знайдена $1 заявка";
@ -235,18 +239,18 @@
"friends_many" = "$1 друзів"; "friends_many" = "$1 друзів";
"friends_other" = "$1 друзів"; "friends_other" = "$1 друзів";
"friends_list_zero" = "У вас поки немає друзів";
"friends_list_one" = "У Вас $1 друг";
"friends_list_few" = "У Вас $1 друг";
"friends_many" = "$1 друзів";
"friends_other" = "$1 друзів";
"friends_online_zero" = "Жодного друга онлайн"; "friends_online_zero" = "Жодного друга онлайн";
"friends_online_one" = "$1 друг онлайн"; "friends_online_one" = "$1 друг онлайн";
"friends_online_few" = "$1 друга онлайн"; "friends_online_few" = "$1 друга онлайн";
"friends_online_many" = "$1 друзів онлайн"; "friends_online_many" = "$1 друзів онлайн";
"friends_online_other" = "$1 друзів онлайн"; "friends_online_other" = "$1 друзів онлайн";
"friends_list_zero" = "У вас поки немає друзів";
"friends_list_one" = "У Вас $1 друг";
"friends_list_few" = "У Вас $1 друг";
"friends_many" = "$1 друзів";
"friends_other" = "$1 друзів";
"followers_zero" = "Жодного підписника"; "followers_zero" = "Жодного підписника";
"followers_one" = "$1 підписник"; "followers_one" = "$1 підписник";
"followers_few" = "$1 підписника"; "followers_few" = "$1 підписника";
@ -1122,6 +1126,17 @@
"admin_commerce_disabled" = "Комерція відключена системним адміністратором"; "admin_commerce_disabled" = "Комерція відключена системним адміністратором";
"admin_commerce_disabled_desc" = "Налаштування ваучерів та подарунків будуть збережені, але не матимуть впливу."; "admin_commerce_disabled_desc" = "Налаштування ваучерів та подарунків будуть збережені, але не матимуть впливу.";
"admin_banned_links" = "Заблоковані посилання";
"admin_banned_link" = "Посилання";
"admin_banned_domain" = "Домен";
"admin_banned_link_description" = "З протоколом (https://example.org/)";
"admin_banned_link_regexp" = "Регулярний вираз";
"admin_banned_link_regexp_description" = "Підставляється після домену, зазначеного вище. Не заповнюйте, якщо хочете заблокувати весь домен";
"admin_banned_link_reason" = "Причина";
"admin_banned_link_initiator" = "Ініціатор";
"admin_banned_link_not_specified" = "Посилання не зазначено";
"admin_banned_link_not_found" = "Посилання не знайдено";
/* Paginator (deprecated) */ /* Paginator (deprecated) */
"paginator_back" = "Назад"; "paginator_back" = "Назад";
@ -1185,3 +1200,12 @@
"cookies_popup_content" = "Цей веб-сайт використовує cookies для того, щоб ідентифікувати вашу сесію і нічого більше. Ознайомтеся з нашою <a href='/privacy'>політикою конфіденційності</a> для отримання додаткової інформації."; "cookies_popup_content" = "Цей веб-сайт використовує cookies для того, щоб ідентифікувати вашу сесію і нічого більше. Ознайомтеся з нашою <a href='/privacy'>політикою конфіденційності</a> для отримання додаткової інформації.";
"cookies_popup_agree" = "Згоден"; "cookies_popup_agree" = "Згоден";
/* Away */
"url_is_banned" = "Перехід неможливий";
"url_is_banned_comment" = "Адміністрація <b>$1</b> не рекомендує переходити за цим посиланням.";
"url_is_banned_comment_r" = "Адміністрація <b>$1</b> не рекомендує переходити за цим посиланням.<br><br>Підстава: <b>$2</b>";
"url_is_banned_default_reason" = "Посилання, за яким Ви спробували перейти, може вести на сайт, що був створений з метою обману користувачів і отримання шляхом цього неправомірного прибутку.";
"url_is_banned_title" = "Посилання на підозрілий сайт";
"url_is_banned_proceed" = "Перейти за посиланням";

View file

@ -60,6 +60,20 @@ openvk:
susLinks: susLinks:
warnings: true warnings: true
showReason: true showReason: true
maintenanceMode:
all: false
photos: false
videos: false
messenger: false
user: false
group: false
comment: false
gifts: false
apps: false
notes: false
notification: false
support: false
topics: false
ton: ton:
enabled: false enabled: false
address: "🅿" address: "🅿"