Merge branch 'master' into feature-reports

This commit is contained in:
Ilya Prokopenko 2022-02-03 13:58:45 +07:00 committed by GitHub
commit 28008c1f76
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
81 changed files with 2972 additions and 737 deletions

204
Email/verify-email.eml.latte Executable file
View file

@ -0,0 +1,204 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Подтверждение Email</title>
<link rel="stylesheet" href="foundation.css" />
<style>
.container {
border-top: 5px solid pink;
}
</style>
</head>
<body>
<table class="body" data-made-with-foundation="">
<tr>
<td class="float-center" align="center" valign="top">
<center>
<table class="spacer">
<tr>
<td>
&nbsp;
</td>
</tr>
</table>
<table class="container">
<tr>
<td>
<table class="row header">
<tr>
<th class="small-12 large-12 columns first last">
<table>
<tr>
<th>
<table class="spacer">
<tr>
<td>
&nbsp;
</td>
</tr>
</table>
<h4 class="text-center">Подтверждение Email</h4>
</th>
</tr>
</table>
</th>
</tr>
</table>
<table class="row">
<tr>
<th class="small-12 large-12 columns first last">
<table class="row">
<tr>
<td>
<center>
<img src="pictures/lock.jpeg" align="center" class="float-center" width=128 height=128 />
</center>
<table class="spacer">
<tr>
<td>
&nbsp;
</td>
</tr>
</table>
<hr/>
<table class="spacer">
<tr>
<td>
&nbsp;
</td>
</tr>
</table>
<p class="text-left">
Здравствуйте, {$name}! Вы вероятно зарегистрировались на одном из инстансов OpenVK. Чтобы ваш аккаунт активировался, необходимо подтвердить Email.
</p>
<table class="spacer">
<tr>
<td>
&nbsp;
</td>
</tr>
</table>
<table class="button large expand success">
<tr>
<td>
<table>
<tr>
<td>
<center>
<a href="http://{$_SERVER['HTTP_HOST']}/regFinish?key={rawurlencode($key)}" align="center" class="float-center">Подтвердить Email!</a>
</center>
</td>
</tr>
</table>
</td>
</tr>
</table>
<table class="spacer">
<tr>
<td>
&nbsp;
</td>
</tr>
</table>
<p class="text-left">
Если кнопка не работает, вы можете попробовать скопировать и вставить эту ссылку в адресную строку вашего веб-обозревателя:
</p>
<table class="callout">
<tr>
<th class="callout-inner primary">
<a href="http://{$_SERVER['HTTP_HOST']}/regFinish?key={$key}" style="color: #000; text-decoration: none;">
http://{$_SERVER['HTTP_HOST']}/regFinish?key={$key}
</a>
</th>
</tr>
</table>
<p class="text-left">
Обратите внимание на то, что эту ссылку нельзя:
</p>
<ul>
<li>Передавать другим людям (даже друзьям, питомцам, соседам, любимым девушкам)</li>
<li>Использовать, если прошло более двух дней с её генерации</li>
</ul>
<table class="callout">
<tr>
<th class="callout-inner alert">
<p>
Ещё раз <b>обратите внимание</b> на то, что данную ссылку или письмо <b>ни в коем случае нельзя</b> передавать другим людям! Даже если они представляются службой поддержки.<br/>
Это письмо предназначено исключительно для одноразового, <b>непосредственного</b> использования владельцем аккаунта.
</p>
</th>
</tr>
</table>
<table class="spacer">
<tr>
<td>
&nbsp;
</td>
</tr>
</table>
<p class="text-right">
С уважением, овк-тян.
</p>
<table class="spacer">
<tr>
<td>
&nbsp;
</td>
</tr>
</table>
<hr/>
<table class="spacer">
<tr>
<td>
&nbsp;
</td>
</tr>
</table>
<p class="text-left">
<small>
Вы получили это письмо так как кто-то или вы зарегистрировались на инстансе OpenVK. Это не рассылка и от неё нельзя отписаться. Если вы всё равно хотите перестать получать подобные письма, деактивируйте ваш аккаунт.
</small>
</p>
</td>
</tr>
</table>
</th>
</tr>
</table>
</td>
</tr>
</table>
<table class="spacer">
<tr>
<td>
&nbsp;
</td>
</tr>
</table>
</center>
</td>
</tr>
</table>
</body>
</html>

View file

@ -31,18 +31,24 @@ If you want, you can add your instance to the list above so that people can regi
### Installation procedure
1. Install PHP 7.4, web-server, Composer, Node.js, Yarn and [Chandler](https://github.com/openvk/chandler)
* PHP 8 has **not** yet been tested, so you should not expect it to work.
* PHP 8 has **not** yet been tested, so you should not expect it to work.
2. Install [commitcaptcha](https://github.com/openvk/commitcaptcha) and OpenVK as Chandler extensions like this:
```
```bash
git clone https://github.com/openvk/openvk /path/to/chandler/extensions/available/openvk
git clone https://github.com/openvk/commitcaptcha /path/to/chandler/extensions/available/commitcaptcha
```
3. And enable them:
```
```bash
ln -s /path/to/chandler/extensions/available/commitcaptcha /path/to/chandler/extensions/enabled/
ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions/enabled/
```
4. Import `install/init-static-db.sql` to **same database** you installed Chandler to
4. Import `install/init-static-db.sql` to **same database** you installed Chandler to and import all sqls from `install/sqls` to **same database**
5. Import `install/init-event-db.sql` to **separate database**
6. Copy `openvk-example.yml` to `openvk.yml` and change options
7. Run `composer install` in OpenVK directory
@ -50,11 +56,12 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
9. Set `openvk` as your root app in `chandler.yml`
Once you are done, you can login as a system administrator on the network itself (no registration required):
* **Login**: `admin@localhost.localdomain6`
* **Password**: `admin`
* It is recommended to change the password before using the built-in account.
* It is recommended to change the password before using the built-in account.
Full example installation instruction for CentOS 8 is also available [here](docs/centos8_install.md).
Full example installation instruction for CentOS 8 is also available [here](https://docs.openvk.su/openvk_engine/centos8_installation/).
### If my website uses OpenVK, should I publish it's sources?
@ -65,9 +72,10 @@ You also not required to publish source texts of your themepacks and plugins.
## Where can I get assistance?
You may reach out to us via:
* [Bug-tracker](https://github.com/openvk/openvk/projects/1)
* [Ticketing system](https://openvk.su/support?act=new)
* Telegram chat: Go to [our channel](https://t.me/openvkch) and open discussion in our channel menu.
* Telegram chat: Go to [our channel](https://t.me/openvkenglish) and open discussion in our channel menu.
* [Reddit](https://www.reddit.com/r/openvk/)
* [Discussions](https://github.com/openvk/openvk/discussions)

View file

@ -31,18 +31,24 @@ _[English](README.md)_
### Процедура установки
1. Установите PHP 7.4, веб-сервер, Composer, Node.js, Yarn и [Chandler](https://github.com/openvk/chandler)
* PHP 8 еще **не** тестировался, поэтому не стоит ожидать, что он будет работать.
* PHP 8 еще **не** тестировался, поэтому не стоит ожидать, что он будет работать.
2. Установите [commitcaptcha](https://github.com/openvk/commitcaptcha) и OpenVK в качестве расширений Chandler следующим образом:
```
```bash
git clone https://github.com/openvk/openvk /path/to/chandler/extensions/available/openvk
git clone https://github.com/openvk/commitcaptcha /path/to/chandler/extensions/available/commitcaptcha
```
3. И включите их:
```
```bash
ln -s /path/to/chandler/extensions/available/commitcaptcha /path/to/chandler/extensions/enabled/
ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions/enabled/
```
4. Импортируйте `install/init-static-db.sql` в **ту же базу данных**, в которую вы установили Chandler
4. Импортируйте `install/init-static-db.sql` в **ту же базу данных**, в которую вы установили Chandler, и импортируйте все SQL файлы из папки `install/sqls` в **ту же базу данных**
5. Импортируйте `install/init-event-db.sql` в **отдельную базу данных**
6. Скопируйте `openvk-example.yml` в `openvk.yml` и измените параметры
7. Запустите `composer install` в директории OpenVK
@ -50,11 +56,12 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
9. Установите `openvk` в качестве корневого приложения в файле `chandler.yml`
После этого вы можете войти как системный администратор в саму сеть (регистрация не требуется):
* **Логин**: `admin@localhost.localdomain6`
* **Пароль**: `admin`
* Перед использованием встроенной учетной записи рекомендуется сменить пароль.
* Перед использованием встроенной учетной записи рекомендуется сменить пароль.
Полный пример инструкции по установке CentOS 8 также доступен [здесь](docs/centos8_install.md).
Полный пример инструкции по установке CentOS 8 также доступен [здесь](https://docs.openvk.su/openvk_engine/centos8_installation/).
### Если мой сайт использует OpenVK, должен ли я публиковать его исходные тексты?
@ -65,6 +72,7 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
## Где я могу получить помощь?
Вы можете связаться с нами через:
* [Баг-трекер](https://github.com/openvk/openvk/projects/1)
* [Помощь в OVK](https://openvk.su/support?act=new)
* Telegram-чат: Перейдите на [наш канал](https://t.me/openvkch) и откройте обсуждение в меню нашего канала.

View file

@ -110,7 +110,7 @@ final class Wall extends VKAPIRequestHandler
];
}
function post(string $owner_id, string $message, int $from_group = 0, int $signed = 0): object
function post(string $owner_id, string $message = "", int $from_group = 0, int $signed = 0): object
{
$this->requireUser();
@ -130,12 +130,46 @@ final class Wall extends VKAPIRequestHandler
if($canPost == false) $this->fail(15, "Access denied");
$anon = OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["enable"];
if($wallOwner instanceof Club && $from_group == 1 && $signed != 1 && $anon) {
$manager = $wallOwner->getManager($this->getUser());
if($manager)
$anon = $manager->isHidden();
elseif($this->getUser()->getId() === $wallOwner->getOwner()->getId())
$anon = $wallOwner->isOwnerHidden();
} else {
$anon = false;
}
$flags = 0;
if($from_group == 1)
if($from_group == 1 && $wallOwner instanceof Club && $wallOwner->canBeModifiedBy($this->getUser()))
$flags |= 0b10000000;
if($signed == 1)
$flags |= 0b01000000;
// TODO: Compatible implementation of this
try {
$photo = null;
$video = null;
if($_FILES["photo"]["error"] === UPLOAD_ERR_OK) {
$album = null;
if(!$anon && $owner_id > 0 && $owner_id === $this->getUser()->getId())
$album = (new AlbumsRepo)->getUserWallAlbum($wallOwner);
$photo = Photo::fastMake($this->getUser()->getId(), $message, $_FILES["photo"], $album, $anon);
}
if($_FILES["video"]["error"] === UPLOAD_ERR_OK)
$video = Video::fastMake($this->getUser()->getId(), $message, $_FILES["video"], $anon);
} catch(\DomainException $ex) {
$this->fail(-156, "The media file is corrupted");
} catch(ISE $ex) {
$this->fail(-156, "The media file is corrupted or too large ");
}
if(empty($message) && !$photo && !$video)
$this->fail(100, "Required parameter 'message' missing.");
try {
$post = new Post;
$post->setOwner($this->getUser()->getId());
@ -148,6 +182,12 @@ final class Wall extends VKAPIRequestHandler
$this->fail(100, "One of the parameters specified was missing or invalid");
}
if(!is_null($photo))
$post->attach($photo);
if(!is_null($video))
$post->attach($video);
if($wall > 0 && $wall !== $this->user->identity->getId())
(new WallPostNotification($wallOwner, $post, $this->user->identity))->emit();

View file

@ -0,0 +1,10 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Entities;
use openvk\Web\Models\Repositories\Users;
use openvk\Web\Models\RowModel;
use openvk\Web\Util\DateTime;
class EmailVerification extends PasswordReset
{
protected $tableName = "email_verifications";
}

View file

@ -94,4 +94,9 @@ class Note extends Postable
return $cached;
}
function getSource(): string
{
return $this->getRecord()->source;
}
}

View file

@ -34,12 +34,15 @@ class PasswordReset extends RowModel
*/
function isNew(): bool
{
return $this->getRecord()->timestamp > (time() - 301);
return $this->getRecord()->timestamp > (time() - (5 * MINUTE));
}
/**
* Token is valid only for 3 days.
*/
function isStillValid(): bool
{
return $this->getRecord()->timestamp > (time() - 172801);
return $this->getRecord()->timestamp > (time() - (3 * DAY));
}
function verify(string $token): bool

View file

@ -127,5 +127,10 @@ class TicketComment extends RowModel
return $mark === 1;
}
function isDeleted(): bool
{
return (bool) $this->getRecord()->deleted;
}
use Traits\TRichText;
}

View file

@ -32,10 +32,12 @@ trait TRichText
private function formatLinks(string &$text): string
{
return preg_replace_callback(
"%(([A-z]++):\/\/(\S*?\.\S*?))([\s)\[\]{},;\"\'<]|\.\s|$)%",
"%(([A-z]++):\/\/(\S*?\.\S*?))([\s)\[\]{},\"\'<]|\.\s|$)%",
(function (array $matches): string {
$href = str_replace("#", "&num;", $matches[1]);
$href = str_replace(";", "&#59;", $matches[1]);
$link = str_replace("#", "&num;", $matches[3]);
$link = str_replace(";", "&#59;", $matches[3]);
$rel = $this->isAd() ? "sponsored" : "ugc";
return "<a href='$href' rel='$rel' target='_blank'>$link</a>" . htmlentities($matches[4]);

View file

@ -850,10 +850,10 @@ class User extends RowModel
function isDeleted(): bool
{
if ($this->getRecord()->deleted == 1)
return TRUE;
else
return FALSE;
if ($this->getRecord()->deleted == 1)
return TRUE;
else
return FALSE;
}
/**
@ -882,6 +882,12 @@ class User extends RowModel
{
return $this->getRecord()->website;
}
// ты устрица
function isActivated(): bool
{
return (bool) $this->getRecord()->activated;
}
use Traits\TSubscribable;
}

View file

@ -4,7 +4,6 @@ namespace openvk\Web\Models\Repositories;
// use openvk\Web\Models\Entities\User;
// use openvk\Web\Models\Repositories\Users;
use openvk\Web\Models\Entities\TicketComment;
use Nette\Database\Table\ActiveRow;
use Chandler\Database\DatabaseConnection;
class TicketComments
@ -20,7 +19,7 @@ class TicketComments
function getCommentsById(int $ticket_id): \Traversable
{
foreach($this->comments->where(['ticket_id' => $ticket_id]) as $comment) yield new TicketComment($comment);
foreach($this->comments->where(['ticket_id' => $ticket_id, 'deleted' => 0]) as $comment) yield new TicketComment($comment);
}
// private function toTicket(?ActiveRow $ar): ?Ticket

View file

@ -39,7 +39,7 @@ class Users
function find(string $query): Util\EntityStream
{
$query = "%$query%";
$result = $this->users->where("CONCAT_WS(' ', first_name, last_name) LIKE ?", $query);
$result = $this->users->where("CONCAT_WS(' ', first_name, last_name) LIKE ?", $query)->where("deleted", 0);
return new Util\EntityStream("User", $result);
}

View file

@ -0,0 +1,33 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Repositories;
use Chandler\Database\DatabaseConnection;
use openvk\Web\Models\Entities\EmailVerification;
use openvk\Web\Models\Entities\User;
use Nette\Database\Table\ActiveRow;
class Verifications
{
private $context;
private $verifications;
function __construct()
{
$this->context = DatabaseConnection::i()->getContext();
$this->verifications = $this->context->table("email_verifications");
}
function toEmailVerification(?ActiveRow $ar): ?EmailVerification
{
return is_null($ar) ? NULL : new EmailVerification($ar);
}
function getByToken(string $token): ?EmailVerification
{
return $this->toEmailVerification($this->verifications->where("key", $token)->fetch());
}
function getLatestByUser(User $user): ?EmailVerification
{
return $this->toEmailVerification($this->verifications->where("profile", $user->getId())->order("timestamp DESC")->fetch());
}
}

View file

@ -8,6 +8,7 @@ use Chandler\Session\Session;
final class AboutPresenter extends OpenVKPresenter
{
protected $banTolerant = true;
protected $activationTolerant = true;
function renderIndex(): void
{
@ -63,7 +64,7 @@ final class AboutPresenter extends OpenVKPresenter
$this->template->usersStats = (new Users)->getStatistics();
$this->template->clubsCount = (new Clubs)->getCount();
$this->template->postsCount = (new Posts)->getCount();
$this->template->popularClubs = (new Clubs)->getPopularClubs();
$this->template->popularClubs = iterator_to_array((new Clubs)->getPopularClubs());
$this->template->admins = iterator_to_array((new Users)->getInstanceAdmins());
}

View file

@ -109,6 +109,7 @@ final class AdminPresenter extends OpenVKPresenter
$club->setAbout($this->postParam("about"));
$club->setShortCode($this->postParam("shortcode"));
$club->setVerified(empty($this->postParam("verify") ? 0 : 1));
$club->setHide_From_Global_Feed(empty($this->postParam("hide_from_global_feed") ? 0 : 1));
$club->save();
break;
case "ban":

View file

@ -3,9 +3,11 @@ namespace openvk\Web\Presenters;
use openvk\Web\Models\Entities\IP;
use openvk\Web\Models\Entities\User;
use openvk\Web\Models\Entities\PasswordReset;
use openvk\Web\Models\Entities\EmailVerification;
use openvk\Web\Models\Repositories\IPs;
use openvk\Web\Models\Repositories\Users;
use openvk\Web\Models\Repositories\Restores;
use openvk\Web\Models\Repositories\Verifications;
use openvk\Web\Util\Validator;
use Chandler\Session\Session;
use Chandler\Security\User as ChandlerUser;
@ -16,19 +18,22 @@ use lfkeitel\phptotp\{Base32, Totp};
final class AuthPresenter extends OpenVKPresenter
{
protected $banTolerant = true;
protected $activationTolerant = true;
private $authenticator;
private $db;
private $users;
private $restores;
private $verifications;
function __construct(Users $users, Restores $restores)
function __construct(Users $users, Restores $restores, Verifications $verifications)
{
$this->authenticator = Authenticator::i();
$this->db = DatabaseConnection::i()->getContext();
$this->users = $users;
$this->restores = $restores;
$this->verifications = $verifications;
parent::__construct();
}
@ -81,7 +86,7 @@ final class AuthPresenter extends OpenVKPresenter
$this->flashFail("err", tr("invalid_email_address"), tr("invalid_email_address_comment"));
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"));
$chUser = ChandlerUser::create($this->postParam("email"), $this->postParam("password"));
if(!$chUser)
@ -96,12 +101,25 @@ final class AuthPresenter extends OpenVKPresenter
$user->setSince(date("Y-m-d H:i:s"));
$user->setRegistering_Ip(CONNECTING_IP);
$user->setBirthday(strtotime($this->postParam("birthday")));
$user->setActivated((int) !OPENVK_ROOT_CONF['openvk']['preferences']['security']['requireEmail']);
$user->save();
if(!is_null($referer)) {
$user->toggleSubscription($referer);
$referer->toggleSubscription($user);
}
if (OPENVK_ROOT_CONF['openvk']['preferences']['security']['requireEmail']) {
$verification = new EmailVerification;
$verification->setProfile($user->getId());
$verification->save();
$params = [
"key" => $verification->getKey(),
"name" => $user->getCanonicalName(),
];
$this->sendmail($user->getEmail(), "verify-email", $params); #Vulnerability possible
}
$this->authenticator->authenticate($chUser->getId());
$this->redirect("/id" . $user->getId(), static::REDIRECT_TEMPORARY);
@ -126,6 +144,10 @@ final class AuthPresenter extends OpenVKPresenter
if(!$this->authenticator->verifyCredentials($user->id, $this->postParam("password")))
$this->flashFail("err", tr("login_failed"), tr("invalid_username_or_password"));
$ovkUser = new User($user->related("profiles.user")->fetch());
if($ovkUser->isDeleted())
$this->flashFail("err", tr("login_failed"), tr("invalid_username_or_password"));
$secret = $user->related("profiles.user")->fetch()["2fa_secret"];
$code = $this->postParam("code");
if(!is_null($secret)) {
@ -136,7 +158,6 @@ final class AuthPresenter extends OpenVKPresenter
if(is_null($code))
return;
$ovkUser = new User($user->related("profiles.user")->fetch());
if(!($code === (new Totp)->GenerateToken(Base32::decode($secret)) || $ovkUser->use2faBackupCode((int) $code))) {
$this->flash("err", tr("login_failed"), tr("incorrect_2fa_code"));
return;
@ -229,7 +250,7 @@ final class AuthPresenter extends OpenVKPresenter
}
$user = $this->users->getByChandlerUser(new ChandlerUser($uRow));
if(!$user)
if(!$user || $user->isDeleted())
$this->flashFail("err", tr("error"), tr("password_reset_error"));
$request = $this->restores->getLatestByUser($user);
@ -250,4 +271,48 @@ final class AuthPresenter extends OpenVKPresenter
$this->flashFail("succ", tr("information_-1"), tr("password_reset_email_sent"));
}
}
function renderResendEmail(): void
{
if(!is_null($this->user) && $this->user->identity->isActivated())
$this->redirect("/id" . $this->user->id, static::REDIRECT_TEMPORARY);
if($_SERVER["REQUEST_METHOD"] === "POST") {
$user = $this->user->identity;
if(!$user || $user->isDeleted() || $user->isActivated())
$this->flashFail("err", tr("error"), tr("email_error"));
$request = $this->verifications->getLatestByUser($user);
if(!is_null($request) && $request->isNew())
$this->flashFail("err", tr("forbidden"), tr("email_rate_limit_error"));
$verification = new EmailVerification;
$verification->setProfile($user->getId());
$verification->save();
$params = [
"key" => $verification->getKey(),
"name" => $user->getCanonicalName(),
];
$this->sendmail($user->getEmail(), "verify-email", $params); #Vulnerability possible
$this->flashFail("succ", tr("information_-1"), tr("email_sent"));
}
}
function renderVerifyEmail(): void
{
$request = $this->verifications->getByToken(str_replace(" ", "+", $this->queryParam("key")));
if(!$request || !$request->isStillValid()) {
$this->flash("err", tr("token_manipulation_error"), tr("token_manipulation_error_comment"));
$this->redirect("/");
} else {
$user = $request->getUser();
$user->setActivated(1);
$user->save();
$this->flash("success", tr("email_verify_success"));
$this->redirect("/");
}
}
}

View file

@ -207,6 +207,7 @@ final class GroupPresenter extends OpenVKPresenter
$club->setShortcode(empty($this->postParam("shortcode")) ? NULL : $this->postParam("shortcode"));
$club->setWall(empty($this->postParam("wall")) ? 0 : 1);
$club->setAdministrators_List_Display(empty($this->postParam("administrators_list_display")) ? 0 : $this->postParam("administrators_list_display"));
$club->setEveryone_Can_Create_Topics(empty($this->postParam("everyone_can_create_topics")) ? 0 : 1);
$club->setDisplay_Topics_Above_Wall(empty($this->postParam("display_topics_above_wall")) ? 0 : 1);
$club->setHide_From_Global_Feed(empty($this->postParam("hide_from_global_feed")) ? 0 : 1);

View file

@ -1,6 +1,7 @@
<?php declare(strict_types=1);
namespace openvk\Web\Presenters;
use MessagePack\MessagePack;
use Chandler\Session\Session;
final class InternalAPIPresenter extends OpenVKPresenter
{
@ -68,4 +69,28 @@ final class InternalAPIPresenter extends OpenVKPresenter
$this->fail(-32603, "Uncaught " . get_class($ex));
}
}
function renderTimezone() {
if($_SERVER["REQUEST_METHOD"] !== "POST")
exit("ты дебил это метод апи");
$sessionOffset = Session::i()->get("_timezoneOffset");
if(is_numeric($this->postParam("timezone", false))) {
$postTZ = intval($this->postParam("timezone", false));
if ($postTZ != $sessionOffset || $sessionOffset == null) {
Session::i()->set("_timezoneOffset", $postTZ ? $postTZ : 3 * MINUTE );
$this->returnJson([
"success" => 1 // If it's new value
]);
} else {
$this->returnJson([
"success" => 2 // If it's the same value (if for some reason server will call this func)
]);
}
} else {
$this->returnJson([
"success" => 0
]);
}
}
}

View file

@ -67,6 +67,35 @@ final class NotesPresenter extends OpenVKPresenter
$note->setCreated(time());
$note->setName($this->postParam("name"));
$note->setSource($this->postParam("html"));
$note->setEdited(time());
$note->save();
$this->redirect("/note" . $this->user->id . "_" . $note->getVirtualId());
}
}
function renderEdit(int $owner, int $note_id): void
{
$this->assertUserLoggedIn();
$this->willExecuteWriteAction();
$note = $this->notes->getNoteById($owner, $note_id);
if(!$note || $note->getOwner()->getId() !== $owner || $note->isDeleted())
$this->notFound();
if(is_null($this->user) || !$note->canBeModifiedBy($this->user->identity))
$this->flashFail("err", "Ошибка доступа", "Недостаточно прав для модификации данного ресурса.");
$this->template->note = $note;
if($_SERVER["REQUEST_METHOD"] === "POST") {
if(empty($this->postParam("name"))) {
$this->flashFail("err", tr("error"), tr("error_segmentation"));
}
$note->setName($this->postParam("name"));
$note->setSource($this->postParam("html"));
$note->setCached_Content(NULL);
$note->setEdited(time());
$note->save();
$this->redirect("/note" . $this->user->id . "_" . $note->getVirtualId());

View file

@ -8,10 +8,12 @@ use Latte\Engine as TemplatingEngine;
use openvk\Web\Models\Entities\IP;
use openvk\Web\Themes\Themepacks;
use openvk\Web\Models\Repositories\{IPs, Users, APITokens, Tickets, Reports};
use WhichBrowser;
abstract class OpenVKPresenter extends SimplePresenter
{
protected $banTolerant = false;
protected $activationTolerant = false;
protected $errorTemplate = "@error";
protected $user = NULL;
@ -34,9 +36,12 @@ abstract class OpenVKPresenter extends SimplePresenter
]));
}
protected function setTempTheme(string $theme): void
protected function setSessionTheme(string $theme, bool $once = false): void
{
Session::i()->set("_tempTheme", $theme);
if($once)
Session::i()->set("_tempTheme", $theme);
else
Session::i()->set("_sessionTheme", $theme);
}
protected function flashFail(string $type, string $title, ?string $message = NULL, ?int $code = NULL, bool $json = false): void
@ -197,6 +202,7 @@ abstract class OpenVKPresenter extends SimplePresenter
$user = Authenticator::i()->getUser();
$this->template->isXmas = intval(date('d')) >= 1 && date('m') == 12 || intval(date('d')) <= 15 && date('m') == 1 ? true : false;
$this->template->isTimezoned = Session::i()->get("_timezoneOffset");
if(!is_null($user)) {
$this->user = (object) [];
@ -205,12 +211,52 @@ abstract class OpenVKPresenter extends SimplePresenter
$this->user->id = $this->user->identity->getId();
$this->template->thisUser = $this->user->identity;
$this->template->userTainted = $user->isTainted();
if($this->user->identity->isDeleted()) {
/*
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⠶⠶⣶⠶⠶⠶⠶⠶⠶⠶⠶⠶⢶⠶⠶⠶⠤⠤⠤⠤⣄⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⣠⡾⠋⠀⠀⠊⠀⠀⠀⠀⠀⠀⠀⠀⠒⠒⠒⠀⠀⠀⠀⠤⢤⣤⣄⠉⠉⠛⠛⠷⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⣰⠟⠀⠀⠀⠀⠀⠐⠋⢑⣤⣶⣶⣤⡢⡀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣄⡂⠀⠀⠶⢄⠙⢷⣤⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⣸⡿⠚⠉⡀⠀⠀⠀⠀⢰⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⢢⠀⠀⡀⣰⣿⣿⣿⣿⣦⡀⠀⠀⠡⡀⢹⡆⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢀⣴⠏⠀⣀⣀⣀⡤⢤⣄⣠⣿⣿⣿⣿⣻⣿⣿⣷⠀⢋⣾⠈⠙⣶⠒⢿⣿⣿⣿⣿⡿⠟⠃⠀⡀⠡⠼⣧⡀⠀⠀⠀⠀⠀⠀
⠀⠀⢀⣴⣿⢃⡴⢊⢽⣶⣤⣀⠀⠊⠉⠉⡛⢿⣿⣿⣿⠿⠋⢀⡀⠁⠀⠀⢸⣁⣀⣉⣉⣉⡉⠀⠩⡡⠀⣩⣦⠀⠈⠻⣦⡀⠀⠀⠀⠀
⠀⢠⡟⢡⠇⡞⢀⠆⠀⢻⣿⣿⣷⣄⠀⢀⠈⠂⠈⢁⡤⠚⡟⠉⠀⣀⣀⠀⠈⠳⣍⠓⢆⢀⡠⢀⣨⣴⣿⣿⡏⢀⡆⠀⢸⡇⠀⠀⠀⠀
⠀⣾⠁⢸⠀⠀⢸⠀⠀⠀⠹⣿⣿⣿⣿⣶⣬⣦⣤⡈⠀⠀⠇⠀⠛⠉⣩⣤⣤⣤⣿⣤⣤⣴⣾⣿⣿⣿⣿⣿⣧⠞⠀⠀⢸⡇⠀⠀⠀⠀
⠀⢹⣆⠸⠀⠀⢸⠀⠀⠀⠀⠘⢿⣿⣿⣿⣿⣿⣿⣟⣛⠛⠛⣛⡛⠛⠛⣛⣋⡉⠉⣡⠶⢾⣿⣿⣿⣿⣿⣿⡇⠀⠀⢀⣾⠃⠀⠀⠀⠀
⠀⠀⠻⣆⡀⠀⠈⢂⠀⠀⠀⠠⡈⢻⣿⣿⣿⣿⡟⠁⠈⢧⡼⠉⠙⣆⡞⠁⠈⢹⣴⠃⠀⢸⣿⣿⣿⣿⣿⣿⠃⠀⡆⣾⠃⠀⠀⠀⠀⠀
⠀⠀⠀⠈⢻⣇⠀⠀⠀⠀⠀⠀⢡⠀⠹⣿⣿⣿⣷⡀⠀⣸⡇⠀⠀⣿⠁⠀⠀⠘⣿⠀⠀⠘⣿⣿⣿⣿⣿⣿⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠹⣇⠀⠠⠀⠀⠀⠀⠡⠐⢬⡻⣿⣿⣿⣿⣿⣷⣶⣶⣿⣦⣤⣤⣤⣿⣦⣶⣿⣿⣿⣿⣿⣿⣿⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠹⣧⡀⠡⡀⠀⠀⠀⠑⠄⠙⢎⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⠀⢿⡇⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠈⠳⣤⡐⡄⠀⠀⠀⠈⠂⠀⠱⣌⠻⣿⣿⣿⣿⣿⣿⣿⠿⣿⠟⢻⡏⢻⣿⣿⣿⣿⣿⣿⣿⠀⢸⡇⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⢮⣦⡀⠂⠀⢀⠀⠀⠈⠳⣈⠻⣿⣿⣿⡇⠘⡄⢸⠀⠀⣇⠀⣻⣿⣿⣿⣿⣿⡏⠀⠸⡇⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⢶⣤⣄⡑⠄⠀⠀⠈⠑⠢⠙⠻⢷⣶⣵⣞⣑⣒⣋⣉⣁⣻⣿⠿⠟⠱⠃⡸⠀⣧⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⣷⣄⡀⠐⠢⣄⣀⡀⠀⠉⠉⠉⠉⠛⠙⠭⠭⠄⠒⠈⠀⠐⠁⢀⣿⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠷⢦⣤⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣒⡠⠄⣠⡾⠃⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠙⠛⠷⠶⣦⣤⣭⣤⣬⣭⣭⣴⠶⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀
*/
Authenticator::i()->logout();
Session::i()->set("_su", NULL);
$this->flashFail("err", tr("error"), tr("profile_not_found"));
$this->redirect("/", static::REDIRECT_TEMPORARY);
}
if($this->user->identity->isBanned() && !$this->banTolerant) {
header("HTTP/1.1 403 Forbidden");
$this->getTemplatingEngine()->render(__DIR__ . "/templates/@banned.xml", [
"thisUser" => $this->user->identity,
"csrfToken" => $GLOBALS["csrfToken"],
"isTimezoned" => Session::i()->get("_timezoneOffset"),
]);
exit;
}
// ето для емейл уже надо (и по хорошему надо бы избавится от повторяющегося кода мда)
if(!$this->user->identity->isActivated() && !$this->activationTolerant) {
header("HTTP/1.1 403 Forbidden");
$this->getTemplatingEngine()->render(__DIR__ . "/templates/@email.xml", [
"thisUser" => $this->user->identity,
"csrfToken" => $GLOBALS["csrfToken"],
"isTimezoned" => Session::i()->get("_timezoneOffset"),
]);
exit;
}
@ -236,10 +282,17 @@ abstract class OpenVKPresenter extends SimplePresenter
{
parent::onBeforeRender();
$whichbrowser = new WhichBrowser\Parser(getallheaders());
$mobiletheme = OPENVK_ROOT_CONF["openvk"]["preferences"]["defaultMobileTheme"];
if($mobiletheme && $whichbrowser->isType('mobile') && Session::i()->get("_tempTheme") == null)
$this->setSessionTheme($mobiletheme);
$theme = NULL;
if(Session::i()->get("_tempTheme")) {
$theme = Themepacks::i()[Session::i()->get("_tempTheme", "ovk")];
Session::i()->set("_tempTheme", NULL);
} else if(Session::i()->get("_sessionTheme")) {
$theme = Themepacks::i()[Session::i()->get("_sessionTheme", "ovk")];
} else if($this->requestParam("themePreview")) {
$theme = Themepacks::i()[$this->requestParam("themePreview")];
} else if($this->user->identity !== null && $this->user->identity->getTheme()) {

View file

@ -6,7 +6,7 @@ use openvk\Web\Models\Entities\TicketComment;
use openvk\Web\Models\Repositories\TicketComments;
use openvk\Web\Util\Telegram;
use Chandler\Session\Session;
use Netcarver\Textile;
use Parsedown;
final class SupportPresenter extends OpenVKPresenter
{
@ -204,10 +204,10 @@ final class SupportPresenter extends OpenVKPresenter
{
$lang = Session::i()->get("lang", "ru");
$base = OPENVK_ROOT . "/data/knowledgebase";
if(file_exists("$base/$name.$lang.textile"))
$file = "$base/$name.$lang.textile";
else if(file_exists("$base/$name.textile"))
$file = "$base/$name.textile";
if(file_exists("$base/$name.$lang.md"))
$file = "$base/$name.$lang.md";
else if(file_exists("$base/$name.md"))
$file = "$base/$name.md";
else
$this->notFound();
@ -219,11 +219,34 @@ final class SupportPresenter extends OpenVKPresenter
array_shift($lines);
}
$content = implode("\r\n", $lines);
$content = implode($lines);
$parser = new Textile\Parser;
$parser = new Parsedown();
$this->template->heading = $heading;
$this->template->content = $parser->parse($content);
$this->template->content = $parser->text($content);
}
function renderDeleteComment(int $id): void
{
$this->assertUserLoggedIn();
$this->assertNoCSRF();
$comment = $this->comments->get($id);
if(is_null($comment))
$this->notFound();
$ticket = $comment->getTicket();
if($ticket->isDeleted())
$this->notFound();
if(!($ticket->getUserId() === $this->user->id && $comment->getUType() === 0))
$this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0);
$this->willExecuteWriteAction();
$comment->delete();
$this->flashFail("succ", tr("ticket_changed"), tr("ticket_changed_comment"));
}
function renderRateAnswer(int $id, int $mark): void

View file

@ -353,8 +353,8 @@ final class UserPresenter extends OpenVKPresenter
} else if($_GET['act'] === "interface") {
if (isset(Themepacks::i()[$this->postParam("style")]) || $this->postParam("style") === Themepacks::DEFAULT_THEME_ID)
{
$user->setStyle($this->postParam("style"));
$this->setTempTheme($this->postParam("style"));
if ($this->postParam("theme_for_session") != "1") $user->setStyle($this->postParam("style"));
$this->setSessionTheme($this->postParam("style"));
}
if ($this->postParam("style_avatar") <= 2 && $this->postParam("style_avatar") >= 0)

View file

@ -0,0 +1,19 @@
{extends "@layout.xml"}
{block title}{_ec_header}{/block}
{block header}
{_ec_header}
{/block}
{block content}
<div class="border-block center">
<h4>{_ec_title}</h4>
<p>{tr("ec_1", htmlentities($thisUser->getCanonicalName()))|noescape}<br/></p>
<p>{_ec_2}</p>
<p>
<form action="/reg/resend" method="post">
<input type="submit" class="button" value="{_ec_resend}">
</form>
</p>
</div>
{/block}

View file

@ -17,6 +17,10 @@
{script "js/l10n.js"}
{script "js/openvk.cls.js"}
{if $isTimezoned == null}
{script "js/timezone.js"}
{/if}
{ifset $thisUser}
{if $thisUser->getNsfwTolerance() < 2}
{css "css/nsfw-posts.css"}
@ -89,14 +93,14 @@
<div class="dimmer"></div>
<div class="toTop">
Вверх
{_to_top}
</div>
<div class="layout">
<div id="xhead" class="dm"></div>
<div class="page_header {if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME}page_custom_header{/if}">
<a href="/" class="home_button {if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME}home_button_custom{/if}" title="{$instance_name}">{$instance_name}</a>
<div n:if="isset($thisUser) ? !$thisUser->isBanned() : true" class="header_navigation">
<div n:if="isset($thisUser) ? (!$thisUser->isBanned() XOR !$thisUser->isActivated()) : true" class="header_navigation">
{ifset $thisUser}
<div class="link">
<a href="/">{_header_home}</a>
@ -138,7 +142,7 @@
<div class="sidebar">
<div class="navigation">
{ifset $thisUser}
{if !$thisUser->isBanned()}
{if !$thisUser->isBanned() XOR !$thisUser->isActivated()}
<a href="/edit" class="link edit-button">{_edit_button}</a>
<a href="{$thisUser->getURL()}" class="link">{_my_page}</a>
<a href="/friends{$thisUser->getId()}" class="link">{_my_friends}
@ -190,8 +194,14 @@
<a n:if="OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['enable'] && $thisUser->getLeftMenuItemStatus('poster')" href="{php echo OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['link']}" >
<img src="{php echo OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['src']}" alt="{php echo OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['caption']}" class="psa-poster" style="max-width: 100%; margin-top: 50px;" />
</a>
{elseif !$thisUser->isActivated()}
<a href="/logout?hash={urlencode($csrfToken)}" class="link">{_menu_logout}</a>
{else}
<a href="/support" class="link">{_menu_support}</a>
<a href="/support" class="link">{_menu_support}
{if $ticketAnsweredCount > 0}
(<b>{$ticketAnsweredCount}</b>)
{/if}
</a>
<a href="/logout?hash={urlencode($csrfToken)}" class="link">{_menu_logout}</a>
{/if}
{else}

View file

@ -2,13 +2,17 @@
{block wrap}
<div class="page_wrap">
<div n:ifset="tabs" class="tabs">
<div n:ifset="tabs" n:ifcontent class="tabs">
{include tabs}
</div>
{ifset size}
{include size, x => $dat}
{/ifset}
<div class="container_gray">
{var data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
{if sizeof($data) > 0}
<div class="content" n:foreach="$data as $dat">
<table>
@ -20,32 +24,32 @@
</a>
</td>
<td valign="top" style="width: 100%">
<a href="{include link, x => $dat}">
<b>
{include name, x => $dat}
</b>
</a>
<br/>
{include description, x => $dat}
{ifset infoTable}
{include infoTable, x => $dat}
{else}
<a href="{include link, x => $dat}">
<b>
{include name, x => $dat}
</b>
</a>
<br/>
{include description, x => $dat}
{/ifset}
</td>
<td n:ifset="actions" valign="top" class="action_links" style="width: 150px">
<td n:ifset="actions" valign="top" class="action_links" style="width: 150px; text-transform: lowercase;">
{include actions, x => $dat}
</td>
</tr>
</tbody>
</table>
</div>
<div style="padding: 8px;">
{include "components/paginator.xml", conf => (object) [
"page" => $page,
"count" => $count,
"amount" => sizeof($data),
"perPage" => $perPage ?? OPENVK_DEFAULT_PER_PAGE,
"atBottom" => true,
]}
</div>
{include "components/paginator.xml", conf => (object) [
"page" => $page,
"count" => $count,
"amount" => sizeof($data),
"perPage" => $perPage ?? OPENVK_DEFAULT_PER_PAGE,
"atBottom" => true,
]}
{else}
{ifset customErrorMessage}
{include customErrorMessage}
@ -54,5 +58,9 @@
{/ifset}
{/if}
</div>
{ifset bottom}
{include bottom}
{/ifset}
</div>
{/block}

View file

@ -42,15 +42,17 @@
</tbody>
</table>
<h4>{_most_popular_groups}</h4>
<ol>
<li n:foreach="$popularClubs as $entry" style="margin-top: 5px;">
<a href="{$entry->club->getURL()}">{$entry->club->getName()}</a>
<div>
{tr("participants", $entry->subscriptions)}
</div>
</li>
</ol>
{if sizeof($popularClubs) !== 0}
<h4>{_most_popular_groups}</h4>
<ol>
<li n:foreach="$popularClubs as $entry" style="margin-top: 5px;">
<a href="{$entry->club->getURL()}">{$entry->club->getName()}</a>
<div>
{tr("participants", $entry->subscriptions)}
</div>
</li>
</ol>
{/if}
<h4>{_rules}</h4>
<div style="margin-top: 16px;">

View file

@ -6,9 +6,50 @@
{/block}
{block content}
<div class="navigation">
{foreach $languages as $language}
<a href="language?lg={$language['code']}&hash={urlencode($csrfToken)}" class="link" rel="nofollow"><img src="/assets/packages/static/openvk/img/flags/{$language['flag']}.gif"> {$language['native_name']}</a>
{/foreach}
<style>
.navigation-lang {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(5, 1fr);
}
.navigation-lang .link_new {
display: inline-block;
padding: 25px 25px 20px 25px;
text-decoration: none;
border-top: 1px solid #fff;
color: #000;
border-bottom: 0;
border-left: 0;
border-right: 0;
text-align: center;
font-size: 11px;
cursor: pointer;
background: none;
margin-bottom: 1px;
}
.navigation-lang .link_new:hover {
background-color: #E4E4E4;
border-top: 1px solid #CCCCCC;
}
</style>
<div class="navigation-lang">
{foreach $languages as $language}
{var $result = preg_match("/(.+)\((.+)\)/", $language['native_name'], $name)}
<a href="language?lg={$language['code']}&hash={urlencode($csrfToken)}" class="link_new" rel="nofollow">
<center><img src="/assets/packages/static/openvk/img/flags/{$language['flag']}.gif"></center>
<br>
{if $result == 1}
{$name[1]}
<br>
<small>{$name[2]}</small>
{else}
{$language['native_name']}
{/if}
</a>
{/foreach}
</div>
{/block}

View file

@ -6,7 +6,7 @@
{var css = file_get_contents(OPENVK_ROOT . "/Web/static/js/node_modules/@atlassian/aui/dist/aui/aui-prototyping.css")}
{str_replace("fonts/", "/assets/packages/static/openvk/js/node_modules/@atlassian/aui/dist/aui/fonts/", $css)|noescape}
</style>
<title>{include title}</title>
<title>{include title} - Админ-панель {=OPENVK_ROOT_CONF['openvk']['appearance']['name']}</title>
</head>
<body>
<div id="page">
@ -16,7 +16,7 @@
<div class="aui-header-primary">
<h1 id="logo" class="aui-header-logo aui-header-logo-textonly">
<a href="/admin">
<span class="aui-header-logo-device">OVK</span>
<span class="aui-header-logo-device">{=OPENVK_ROOT_CONF['openvk']['appearance']['name']}</span>
</a>
</h1>
</div>
@ -163,9 +163,7 @@
</div>
<footer id="footer" role="contentinfo">
<section class="footer-body">
<div id="footer-logo">
OpenVK
</div>
OpenVK <a href="/about:openvk">{php echo OPENVK_VERSION}</a> | PHP: {phpversion()} | DB: {\Chandler\Database\DatabaseConnection::i()->getConnection()->getPdo()->getAttribute(\PDO::ATTR_SERVER_VERSION)}
</section>
</footer>
</div>

View file

@ -79,6 +79,12 @@
Верификация
</label>
</div>
<div class="group">
<input class="toggle-large" type="checkbox" id="hide_from_global_feed" name="hide_from_global_feed" value="1" {if $club->isHideFromGlobalFeedEnabled()} checked {/if} />
<label for="hide_from_global_feed">
Не отображать записи в глобальной ленте
</label>
</div>
<hr/>
<div class="buttons-container">
<div class="buttons">

View file

@ -0,0 +1,49 @@
{extends "../@layout.xml"}
{block title}{_edit_note}{/block}
{block header}
{var author = $note->getOwner()}
<a href="{$author->getURL()}">{$author->getCanonicalName()}</a>
»
<a href="/notes{$author->getId()}">{_notes}</a>
»
<a href="/note{$author->getId()}_{$note->getVirtualId()}">{$note->getName()}</a>
{/block}
{block content}
<form id="noteFactory" method="POST">
<input type="text" name="name" placeholder="{_name_note}" style="width:603px;" value="{$note->getName()}" />
<br/><br/>
<textarea name="html" style="display:none;"></textarea>
<div id="editor" style="width:600px;height:300px;border:1px solid grey"></div>
<p><i><a href="/kb/notes">Кое-что</a> из (X)HTML поддерживается.</i></p>
<input type="hidden" name="hash" value="{$csrfToken}" />
<button class="button">{_save}</button>
&nbsp;
<a href="/note{$note->getOwner()->getId()}_{$note->getVirtualId()}" class="button">{_cancel}</a>
</form>
{script "js/node_modules/monaco-editor/min/vs/loader.js"}
{script "js/node_modules/requirejs/bin/r.js"}
<script>
require.config({
paths: {
'vs': '/assets/packages/static/openvk/js/node_modules/monaco-editor/min/vs'
}
});
require(['vs/editor/editor.main'], function() {
window._editor = monaco.editor.create(document.getElementById('editor'), {
value: {$note->getSource()},
lineNumbers: "off",
language: "html"
});
});
document.querySelector("#noteFactory").addEventListener("submit", function() {
document.querySelector("textarea").value = window._editor.getValue();
});
</script>
{/block}

View file

@ -12,46 +12,67 @@
{/block}
{block content}
{var author = $note->getOwner()}
<style>
#userContent img {
max-width: 245pt;
max-height: 200pt;
}
#userContent blockquote {
background-color: #f3f3f3;
border-bottom: 5px solid #969696;
padding: 1;
}
#userContent cite {
margin-top: 1em;
display: block;
}
#userContent cite::before {
content: "— ";
}
</style>
<article id="userContent" style="min-height: 300pt;">
{$note->getText()|noescape}
</article>
<div style="width: 100%; min-height: 100px;">
<div style="float: left; min-height: 100px; width: 70%;">
{include "../components/comments.xml",
comments => $comments,
count => $cCount,
page => $cPage,
model => "notes",
parent => $note}
</div>
<div style="float: right; min-height: 100px; width: 30%;">
<h4>{_actions}</h4>
<div n:if="isset($thisUser) && $thisUser->getId() === $note->getOwner()->getId()">
<a id="_noteDelete" href="/note{$note->getOwner()->getId()}_{$note->getId()}/delete" class="profile_link" style="display:block;width:96%;">{_delete}</a>
<article id="userContent" style="margin: 10px 10px 0;">
<div class="note_header">
<div class="note_title">
<div class="note_title">
<a>{$note->getName()}</a>
</div>
</div>
<div class="byline">
<span><a href="{$author->getURL()}">{$author->getCanonicalName()}</a></span> {$note->getPublicationTime()}
<span n:if="$note->getEditTime() > $note->getPublicationTime()">({_edited} {$note->getEditTime()})</span>
</div>
</div>
<div style="margin-left: 6px; width: 535px;">
{$note->getText()|noescape}
</div>
</article>
<div class="note_footer" style="margin: 10px 10px 0;">
<div class="comments_count">
{if sizeof($comments) > 0}
{_comments} ({$note->getCommentsCount()})
{else}
{_no_comments}
{/if}
<span n:if="isset($thisUser) && $thisUser->getId() === $note->getOwner()->getId()">&nbsp;|&nbsp;
<a id="_noteDelete" href="/note{$note->getOwner()->getId()}_{$note->getId()}/delete">{_delete}</a>
&nbsp;|&nbsp;
<a href="/note{$note->getOwner()->getId()}_{$note->getVirtualId()}/edit">{_edit}</a>
</span>
</div>
</div>
<div style="margin: 6px 10px 10px;border-top: 1px solid #ddd;">
{include "../components/comments.xml",
comments => $comments,
count => $cCount,
page => $cPage,
model => "notes",
parent => $note,
showTitle => false}
</div>
{/block}

View file

@ -28,11 +28,9 @@
{var cover = $x->getCoverPhoto()}
{var preview = is_null($cover) ? "/assets/packages/static/openvk/img/camera_200.png" : $cover->getURL()}
<center style="height: 54pt; width: 140px;">
<a href="/album{$x->getPrettyId()}">
<img src="{$preview}" alt="{$x->getName()}" style="max-height: 100%; max-width: 100%;" />
</a>
</center>
<a href="/album{$x->getPrettyId()}">
<img src="{$preview}" alt="{$x->getName()}" style="height: 130px; width: 170px; object-fit: cover" />
</a>
{/block}
{block name}
@ -40,8 +38,8 @@
{/block}
{block description}
<span>{$x->getDescription() ?? $x->getName()}</span><br/>
<span style="color: grey;">{$x->getPhotosCount()} фотографий</span><br/>
<span style="color: grey;">Создан {$x->getCreationTime()}</span><br/>
<span style="color: grey;">Изменён {$x->getEditTime() ?? $x->getCreationTime()}</span>
<span>{$x->getDescription() ?? $x->getName()}</span><br />
<span style="color: grey;">{$x->getPhotosCount()} фотографий</span><br />
<span style="color: grey;">Обновлен {$x->getEditTime() ?? $x->getCreationTime()}</span><br />
<span style="color: grey;">Создан {$x->getCreationTime()}</span><br />
{/block}

View file

@ -101,11 +101,9 @@
{/if}
</div>
{if $comment->getUType() === 0}
<div class="post-menu">
<a href="/support/comment/{$comment->getId()}/delete">{_delete}</a>
</div>
{/if}
<div class="post-menu">
<a href="/support/comment/{$comment->getId()}/delete?hash={urlencode($csrfToken)}">{_delete}</a>
</div>
{if $comment->getUType() === 1 && !is_null($comment->isLikedByUser())}
<div class="post-menu">

View file

@ -103,7 +103,7 @@
{if $comment->getUType() === 0}
<div class="post-menu">
<a href="/support/comment/{$comment->getId()}/delete">{_delete}</a>
<a href="/support/comment/{$comment->getId()}/delete?hash={urlencode($csrfToken)}">{_delete}</a>
</div>
{/if}

View file

@ -14,8 +14,8 @@
{block tabs}
<form style="margin-left: 12px;">
<input name="query" class="header_search_input" placeholder="{_"header_search"}" value="{$_GET['query'] ?? ''}" style="width: 90%" />
<input type="submit" class="button" value="{_"search_button"}" style="width: 7%" />
<input name="query" class="header_search_input" placeholder="{_"header_search"}" value="{$_GET['query'] ?? ''}" style="width: 86%" />
<input type="submit" class="button" value="{_"search_button"}" style="width: 7.5%" />
</form>
<p style="margin-left: 15px;">

View file

@ -2,37 +2,45 @@
{var iterator = $user->getClubs($page, $admin)}
{var count = $user->getClubCount($admin)}
{block title}{_"groups"}{/block}
{block title}
{_groups}
{/block}
{block header}
<a href="{$user->getURL()}">{$user->getCanonicalName()}</a> » {_"groups"}
<div n:if="!is_null($thisUser) && $user->getId() === $thisUser->getId()" style="float:right;">
<span>
<b>
<a href="/groups_create">
{_"create_group"}
</a>
</b>
</span>
</div>
{if !is_null($thisUser) && $user->getId() === $thisUser->getId()}
{_my_groups}
{else}
<a href="{$user->getURL()}">{$user->getCanonicalName()}</a> » {_groups}
{/if}
{/block}
{* BEGIN ELEMENTS DESCRIPTION *}
{block tabs}
{if !is_null($thisUser) && $user->getId() === $thisUser->getId()}
<div {if !$admin}id="activetabs"{/if} class="tab">
<a {if !$admin}id="act_tab_a"{/if} href="/groups{$user->getId()}">
{_groups}
</a>
</div>
<div {if $admin}id="activetabs"{/if} class="tab">
<a {if $admin}id="act_tab_a"{/if} href="/groups{$user->getId()}?act=managed">
{_managed}
</a>
</div>
{/if}
{if !is_null($thisUser) && $user->getId() === $thisUser->getId()}
<div n:attr='id => ($admin ? false : "activetabs")' class="tab">
<a n:attr='id => ($admin ? false : "act_tab_a")' href="/groups{$user->getId()}">
{_groups}
</a>
</div>
<div n:attr='id => (!$admin ? false : "activetabs")' class="tab">
<a n:attr='id => (!$admin ? false : "act_tab_a")' href="/groups{$user->getId()}?act=managed">
{_managed}
</a>
</div>
{/if}
{/block}
{block size}
<div n:if="!is_null($thisUser) && $user->getId() === $thisUser->getId()" style="padding-bottom: 0px; border-bottom: 0;" class="summaryBar">
<div class="summary">
{if !is_null($thisUser) && $user->getId() === $thisUser->getId()}
{tr("groups_list", $thisUser->getClubCount())}
{else}
{tr("groups", $user->getClubCount())}
{/if}
</div>
</div>
{/block}
{block link|strip|stripHtml}
@ -43,8 +51,19 @@
<img src="{$x->getAvatarUrl()}" width="75" alt="Фотография группы" />
{/block}
{block name}
{$x->getName()}
{block infoTable}
<table id="basicInfo" class="ugc-table group_info" cellspacing="0" cellpadding="0" border="0">
<tbody>
<tr>
<td class="label"><span class="nobold">{_name}: </span></td>
<td class="data"><a href="{$x->getURL()}">{$x->getName()}</a></td>
</tr>
<tr>
<td class="label"><span class="nobold">{_size}:</span></td>
<td class="data"><a href="/club{$x->getId()}/followers">{tr("participants", $x->getFollowersCount())}</a></td>
</tr>
</tbody>
</table>
{/block}
{block description}
@ -54,12 +73,46 @@
{block actions}
{var clubPinned = $thisUser->isClubPinned($x)}
{if $x->canBeModifiedBy($thisUser ?? NULL) && ($clubPinned || $thisUser->getPinnedClubCount() <= 10)}
<a class="profile_link" href="/groups_pin?club={$x->getId()}&hash={rawurlencode($csrfToken)}" id="_pinGroup" data-group-name="{$x->getName()}" data-group-url="{$x->getUrl()}">
<a style="width: 140px;" class="profile_link" href="{$x->getURL()}">
{_check_community}
</a>
<a style="width: 140px;" class="profile_link" href="/groups_pin?club={$x->getId()}&hash={rawurlencode($csrfToken)}" id="_pinGroup" data-group-name="{$x->getName()}" data-group-url="{$x->getUrl()}">
{if $clubPinned}
{_remove_from_left_menu}
{else}
{_add_to_left_menu}
{/if}
</a>
<form action="/setSub/club" method="post">
<input type="hidden" name="act" value="rem" />
<input type="hidden" name="id" value="{$x->getId()}" />
<input type="hidden" name="hash" value="{$csrfToken}" />
<input style="width: 140px; text-transform: lowercase;" type="submit" id="profile_link" value="{_leave_community}" />
</form>
{/if}
{/block}
{block bottom}
{if !is_null($thisUser) && $user->getId() === $thisUser->getId()}
<div class="groups_options">
<div id="gp_container" style="width: 200px; margin-right: 40px;">
<h4>{_open_new_group}</h4>
<span>{_open_group_desc}</span>
<form action="/groups_create">
<button class="button">{_create_group}</button>
</form>
</div>
<div id="gp_container" style="width: 344px;">
<h4>{_search_group}</h4>
<span>{_search_group_desc}</span>
<form action="/search">
<input name="type" type="hidden" value="groups">
<input name="query" class="header_search_input" value="" style="background: none; width: 155px; padding-left: 3px;">
<button class="button">{_search_by_groups}</button>
</form>
</div>
</div>
{/if}
{/block}

View file

@ -462,6 +462,14 @@
</select>
</td>
</tr>
<tr>
<td width="120" valign="top" align="right">
<input type="checkbox" name="theme_for_session" value="1">
</td>
<td>
{_apply_style_for_this_device}
</td>
</tr>
<tr>
<td>

View file

@ -4,10 +4,14 @@
{block header}
{_"feed"}
<div n:if="!isset($globalFeed)" style="float: right;">
<div style="float: right;">
<span>
<b>
<a href="/feed/all">{_"all_news"}</a>
{if !isset($globalFeed)}
<a href="/feed/all">{_"all_news"}</a>
{else}
<a href="/feed">{_"my_feed"}</a>
{/if}
</b>
</span>
</div>

View file

@ -1,7 +1,6 @@
<center>
<img src="/assets/packages/static/openvk/img/error.png" alt="Ошибка" />
<h1>{$title}</h1>
<p>
<center style="background: white;border: #DEDEDE solid 1px;">
<span style="color: #707070;margin: 60px 0;display: block;">
<b>{$title}</b><br><br>
{$description}
</p>
</center>
</span>
</center>

View file

@ -1,16 +1,18 @@
{var $space = 2}
{var $pageCount = ceil($conf->count / $conf->perPage)}
<div n:if="!($conf->page === 1 && $conf->count <= $conf->perPage)" n:class="paginator, ($conf->atBottom ?? false) ? paginator-at-bottom">
{if $conf->page > $space}
<a n:attr="class => ($conf->page === 1 ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => 1]), 'k', '&', PHP_QUERY_RFC3986)}">«</a>
{/if}
{for $j = $conf->page - ($space-1); $j <= $conf->page + ($space-1); $j++}
{if $j > 0 && $j <= $pageCount}
<a n:attr="class => ($conf->page === $j ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => $j]), 'k', '&', PHP_QUERY_RFC3986)}">{$j}</a>
<div n:if="!($conf->page === 1 && $conf->count <= $conf->perPage)" style="padding: 8px;">
<div n:class="paginator, ($conf->atBottom ?? false) ? paginator-at-bottom">
{if $conf->page > $space}
<a n:attr="class => ($conf->page === 1 ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => 1]), 'k', '&', PHP_QUERY_RFC3986)}">«</a>
{/if}
{/for}
{if $conf->page <= $pageCount-$space}
<a n:attr="class => ($conf->page === $pageCount ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => $pageCount]), 'k', '&', PHP_QUERY_RFC3986)}">»</a>
{/if}
{for $j = $conf->page - ($space-1); $j <= $conf->page + ($space-1); $j++}
{if $j > 0 && $j <= $pageCount}
<a n:attr="class => ($conf->page === $j ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => $j]), 'k', '&', PHP_QUERY_RFC3986)}">{$j}</a>
{/if}
{/for}
{if $conf->page <= $pageCount-$space}
<a n:attr="class => ($conf->page === $pageCount ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => $pageCount]), 'k', '&', PHP_QUERY_RFC3986)}">»</a>
{/if}
</div>
</div>

View file

@ -129,7 +129,8 @@
{/foreach}
<div n:ifset="$thisUser" id="commentTextArea{$commentTextAreaId}" n:attr="style => ($commentsCount == 0 ? 'display: none;')" class="commentsTextFieldWrap">
{var commentsURL = "/al_comments/create/posts/" . $post->getId()}
{include "../textArea.xml", route => $commentsURL, postOpts => false, graffiti => (bool) ovkGetQuirk("comments.allow-graffiti"), post => $post}
{var club = is_null($club) ? ($post->getTargetWall() < 0 ? (new openvk\Web\Models\Repositories\Clubs)->get(abs($post->getTargetWall())) : NULL) : $club}
{include "../textArea.xml", route => $commentsURL, postOpts => false, graffiti => (bool) ovkGetQuirk("comments.allow-graffiti"), post => $post, club => $club}
</div>
</div>
{/if}

View file

@ -25,17 +25,17 @@ class DateTime
if($this->timestamp >= strtotime("midnight")) { # Today
if($diff->h >= 1)
return tr("time_today") . tr("time_at_sp") . ovk_strftime_safe("%X", $this->timestamp);
return tr("time_today") . tr("time_at_sp") . ovk_strftime_safe(" %R %p", $this->timestamp);
else if($diff->i < 2)
return tr("time_just_now");
else
return $diff->i === 5 ? tr("time_exactly_five_minutes_ago") : tr("time_minutes_ago", $diff->i);
} else if($this->timestamp >= strtotime("-1day midnight")) { # Yesterday
return tr("time_yesterday") . tr("time_at_sp") . ovk_strftime_safe("%X", $this->timestamp);
} else if(ovk_strftime_safe("%Y", $this->timestamp) === ovk_strftime_safe("%Y")) { # In this year
return tr("time_yesterday") . tr("time_at_sp") . ovk_strftime_safe(" %R %p", $this->timestamp);
} 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 %p", $this->timestamp);
} else {
return ovk_strftime_safe("%e %B %Y ", $this->timestamp) . tr("time_at_sp") . ovk_strftime_safe(" %X", $this->timestamp);
return ovk_strftime_safe("%e %B %Y ", $this->timestamp) . tr("time_at_sp") . ovk_strftime_safe(" %R %p", $this->timestamp);
}
}

View file

@ -34,6 +34,7 @@ services:
- openvk\Web\Models\Repositories\Messages
- openvk\Web\Models\Repositories\Restores
- openvk\Web\Models\Repositories\Reports
- openvk\Web\Models\Repositories\Verifications
- openvk\Web\Models\Repositories\Notifications
- openvk\Web\Models\Repositories\TicketComments
- openvk\Web\Models\Repositories\IPs

View file

@ -9,6 +9,8 @@ routes:
handler: "About->rules"
- url: "/rpc"
handler: "InternalAPI->route"
- url: "/iapi/timezone"
handler: "InternalAPI->timezone"
- url: "/support"
handler: "Support->index"
- url: "/support/tickets"
@ -23,6 +25,8 @@ routes:
handler: "Support->makeComment"
- url: "/al_comments/create/support/reply/{num}"
handler: "Support->AnswerTicketReply"
- url: "/support/comment/{num}/delete"
handler: "Support->deleteComment"
- url: "/al_comments/create/{text}/{num}"
handler: "Comment->makeComment"
- url: "/support/delete/{num}"
@ -55,6 +59,10 @@ routes:
handler: "Auth->restore"
- url: "/restore/internal-finish"
handler: "Auth->finishRestoringPassword"
- url: "/reg/resend"
handler: "Auth->resendEmail"
- url: "/regFinish"
handler: "Auth->verifyEmail"
- url: "/setSID/{slug}"
handler: "Auth->su"
- url: "/settings"
@ -221,6 +229,8 @@ routes:
handler: "Notes->view"
- url: "/notes/create"
handler: "Notes->create"
- url: "/note{num}_{num}/edit"
handler: "Notes->edit"
- url: "/note{num}_{num}/delete"
handler: "Notes->delete"
- url: "/invite"

View file

@ -214,7 +214,7 @@ a {
}
.page_yellowheader a {
color: #C8BF85;
color: #696029;
}
.page_content {
@ -563,6 +563,7 @@ input[type="text"], input[type="password"], input[type~="text"], input[type~="pa
font-size: 11px;
font-family: tahoma, verdana, arial, sans-serif;
width: 100%;
box-sizing: border-box;
}
h4 {
@ -794,9 +795,8 @@ table.User {
.tabs {
border-bottom: 1px solid #707070;
margin-left: -10px;
margin-right: -6px;
width: 627px;
margin-right: -12px;
margin-left: -12px;
}
#activetabs {
@ -1149,6 +1149,7 @@ textarea {
width: 100%;
padding: 4px;
resize: none;
box-sizing: border-box;
}
#faqhead {
@ -1580,11 +1581,10 @@ body.scrolled .toTop:hover {
}
.postFeedWrapper {
margin: -10px;
width: 611px;
padding: 4px 8px;
background-color: rgb(240, 240, 240);
border-bottom: 1px solid #ccc;
border-top: 1px solid #ccc;
}
.user-alert {
@ -1785,3 +1785,93 @@ body.scrolled .toTop:hover {
.hover-box:hover {
background-color: #C0CAD5;
}
.summaryBar {
border-bottom: 1px solid #DAE2E8;
clear: both;
padding: 11px 10px;
color: black;
font-weight: normal;
line-height: normal;
margin-left: -12px;
margin-right: -12px;
}
.summaryBar .summary {
color: #45688E;
font-weight: bold;
padding-top: 3px;
padding-bottom: 4px;
display: inline-block;
}
.note_header {
background: #f7f7f7;
border-bottom: solid 1px #DAE1E8;
border-top: solid 1px #45688E;
padding: 4px 6px 5px 6px;
}
.note_header .note_title {
color: #45688E;
font-size: 13px;
font-weight: bold;
line-height: 15px;
margin: 0;
padding: 0 0 1px 0;
}
.note_footer {
border-top: 1px solid #ddd;
clear: both;
margin-top: 10px;
padding: 0px 2px 0px 6px;
}
.comments_count {
padding: 5px 0px 0px 0px;
}
.groups_options {
padding: 10px 20px 20px;
border-top: #DEDEDE solid 1px;
margin-top: 12px;
margin-left: -12px;
margin-right: -12px;
}
#gp_container {
display: inline-block;
}
#gp_container span {
display: block;
margin: 10px 0 15px;
}
#gp_container h4 {
font-size: 11px;
}
.container_gray .content:last-child {
margin-bottom: 0;
}
.group_info {
padding: 0 0 0 5px !important;
}
.group_info .label {
width: auto !important;
padding-right: 5px;
}
.border-block {
box-shadow: inset 0px 0 0px 1px #b6bfca, inset 0px 0 0px 10px #d8dfe7;
width: 300px;
padding: 20px;
}
.center {
margin: 0 auto;
}

BIN
Web/static/img/flags/su.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

View file

@ -5,7 +5,9 @@ u(".comment-reply").on("click", function(e) {
let fromGroup = Boolean(comment.data("from-group"));
let postId = comment.data("post-id");
let inputbox = postId == null ? u("#write textarea") : u("#wall-post-input" + (postId || ""));
let mention = ("[" + (fromGroup ? "club" : "id") + authorId + "|" + authorNm + "], ");
inputbox.text("[" + (fromGroup ? "club" : "id") + authorId + "|" + authorNm + "], ");
// Substitute pervious mention if present, prepend otherwise
inputbox.nodes[0].value = inputbox.nodes[0].value.replace(/(^\[([A-Za-z0-9]+)\|([\p{L} 0-9@]+)\], |^)/u, mention);
inputbox.trigger("focusin");
});

View file

@ -110,7 +110,7 @@ function setupWallPostInputHandlers(id) {
var textArea = e.target;
textArea.style.height = "5px";
var newHeight = textArea.scrollHeight;
textArea.style.height = newHeight + boost;
textArea.style.height = newHeight + boost + "px";
return;
// revert to original size if it is larger (possibly changed by user)

View file

@ -1,5 +1,5 @@
window.addEventListener("scroll", function(e) {
if(document.body.scrollTop < 100) {
if(window.scrollY < 100) {
document.body.classList.toggle("scrolled", false);
} else {
document.body.classList.toggle("scrolled", true);

11
Web/static/js/timezone.js Executable file
View file

@ -0,0 +1,11 @@
// This file is included only when there is no info about timezone in users's chandler session
xhr = new XMLHttpRequest();
xhr.open("POST", "/iapi/timezone", true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.onload = (response) => {
if(JSON.parse(response.originalTarget.responseText).success == 1) {
window.location.reload();
}
};
xhr.send('timezone=' + new Date().getTimezoneOffset());

View file

@ -167,7 +167,8 @@ function ovk_proc_strtrim(string $string, int $length = 0): string
function ovk_strftime_safe(string $format, ?int $timestamp = NULL): string
{
$str = strftime($format, $timestamp ?? time());
$sessionOffset = intval(Session::i()->get("_timezoneOffset"));
$str = strftime($format, $timestamp + ($sessionOffset * MINUTE) * -1 ?? time() + ($sessionOffset * MINUTE) * -1);
if(PHP_SHLIB_SUFFIX === "dll") {
$enc = tr("__WinEncoding");
if($enc === "@__WinEncoding")
@ -230,7 +231,7 @@ return (function() {
if(is_dir($gitDir = OPENVK_ROOT . "/.git") && $showCommitHash)
$ver = trim(`git --git-dir="$gitDir" log --pretty="%h" -n1 HEAD` ?? "Unknown version") . "-nightly";
else
$ver = "Build 15";
$ver = "Public Technical Preview 3";
// Unix time constants
define('MINUTE', 60);

View file

@ -7,13 +7,13 @@
"james-heinrich/getid3": "^1.9@dev",
"rybakit/msgpack": "dev-master",
"wapmorgan/binary-stream": "dev-master",
"netcarver/textile": "^3.7@dev",
"al/emoji-detector": "dev-master",
"ezyang/htmlpurifier": "dev-master",
"scssphp/scssphp": "dev-master",
"lfkeitel/phptotp": "dev-master",
"chillerlan/php-qrcode": "dev-main",
"vearutop/php-obscene-censor-rus": "dev-master"
"vearutop/php-obscene-censor-rus": "dev-master",
"erusev/parsedown": "dev-master"
},
"minimum-stability": "dev"
}

194
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "770bb7b5fdc8074bb03f5c2a762914fe",
"content-hash": "3816f5fbf2c78a3e252637476cd2ae08",
"packages": [
{
"name": "al/emoji-detector",
@ -58,12 +58,12 @@
"source": {
"type": "git",
"url": "https://github.com/chillerlan/php-qrcode.git",
"reference": "0c1f322476a090b945108e6df960ee381a8c352e"
"reference": "06730361508c283a02bbf9cbc9e4b55e7b3bc88b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/chillerlan/php-qrcode/zipball/0c1f322476a090b945108e6df960ee381a8c352e",
"reference": "0c1f322476a090b945108e6df960ee381a8c352e",
"url": "https://api.github.com/repos/chillerlan/php-qrcode/zipball/06730361508c283a02bbf9cbc9e4b55e7b3bc88b",
"reference": "06730361508c283a02bbf9cbc9e4b55e7b3bc88b",
"shasum": ""
},
"require": {
@ -138,7 +138,7 @@
"type": "ko_fi"
}
],
"time": "2021-12-12T23:34:10+00:00"
"time": "2021-12-14T15:11:20+00:00"
},
{
"name": "chillerlan/php-settings-container",
@ -203,26 +203,74 @@
],
"time": "2021-09-06T15:17:01+00:00"
},
{
"name": "erusev/parsedown",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/erusev/parsedown.git",
"reference": "6598f3860c2698fe2f0f1bc98212fc01d0a1893c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/6598f3860c2698fe2f0f1bc98212fc01d0a1893c",
"reference": "6598f3860c2698fe2f0f1bc98212fc01d0a1893c",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35"
},
"default-branch": true,
"type": "library",
"autoload": {
"psr-0": {
"Parsedown": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"description": "Parser for Markdown.",
"homepage": "http://parsedown.org",
"keywords": [
"markdown",
"parser"
],
"support": {
"issues": "https://github.com/erusev/parsedown/issues",
"source": "https://github.com/erusev/parsedown/tree/master"
},
"time": "2020-08-09T14:12:21+00:00"
},
{
"name": "ezyang/htmlpurifier",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "996eaf43310edf1d908bc0030a18b37b8cf6eefd"
"reference": "12ab42bd6e742c70c0a52f7b82477fcd44e64b75"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/996eaf43310edf1d908bc0030a18b37b8cf6eefd",
"reference": "996eaf43310edf1d908bc0030a18b37b8cf6eefd",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/12ab42bd6e742c70c0a52f7b82477fcd44e64b75",
"reference": "12ab42bd6e742c70c0a52f7b82477fcd44e64b75",
"shasum": ""
},
"require": {
"php": ">=5.2"
},
"require-dev": {
"simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd"
},
"default-branch": true,
"type": "library",
"autoload": {
@ -254,9 +302,9 @@
],
"support": {
"issues": "https://github.com/ezyang/htmlpurifier/issues",
"source": "https://github.com/ezyang/htmlpurifier/tree/master"
"source": "https://github.com/ezyang/htmlpurifier/tree/v4.14.0"
},
"time": "2021-09-07T18:16:55+00:00"
"time": "2021-12-25T01:21:49+00:00"
},
{
"name": "guzzlehttp/guzzle",
@ -357,12 +405,12 @@
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "136a635e2b4a49b9d79e9c8fee267ffb257fdba0"
"reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/136a635e2b4a49b9d79e9c8fee267ffb257fdba0",
"reference": "136a635e2b4a49b9d79e9c8fee267ffb257fdba0",
"url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
"reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
"shasum": ""
},
"require": {
@ -418,7 +466,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/1.5.0"
"source": "https://github.com/guzzle/promises/tree/1.5.1"
},
"funding": [
{
@ -434,7 +482,7 @@
"type": "tidelift"
}
],
"time": "2021-10-07T13:05:22+00:00"
"time": "2021-10-22T20:56:57+00:00"
},
{
"name": "guzzlehttp/psr7",
@ -552,12 +600,12 @@
"source": {
"type": "git",
"url": "https://github.com/JamesHeinrich/getID3.git",
"reference": "a440175a329a83dbfad991e67b5e5f3a1ff51bd9"
"reference": "46346ff3bea96a63f1a1d58ee4eabc79471d0ec8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/a440175a329a83dbfad991e67b5e5f3a1ff51bd9",
"reference": "a440175a329a83dbfad991e67b5e5f3a1ff51bd9",
"url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/46346ff3bea96a63f1a1d58ee4eabc79471d0ec8",
"reference": "46346ff3bea96a63f1a1d58ee4eabc79471d0ec8",
"shasum": ""
},
"require": {
@ -612,7 +660,7 @@
"issues": "https://github.com/JamesHeinrich/getID3/issues",
"source": "https://github.com/JamesHeinrich/getID3/tree/master"
},
"time": "2021-10-07T12:08:13+00:00"
"time": "2022-01-03T16:59:52+00:00"
},
{
"name": "komeiji-satori/curl",
@ -706,66 +754,6 @@
},
"time": "2017-02-06T17:46:14+00:00"
},
{
"name": "netcarver/textile",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/textile/php-textile.git",
"reference": "d64e1f8424afd600cc2732f4f99f262aef55fca2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/textile/php-textile/zipball/d64e1f8424afd600cc2732f4f99f262aef55fca2",
"reference": "d64e1f8424afd600cc2732f4f99f262aef55fca2",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"php-coveralls/php-coveralls": "2.1.*",
"phpunit/phpunit": "5.7.*",
"squizlabs/php_codesniffer": "3.*",
"symfony/yaml": "2.4.*"
},
"default-branch": true,
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.7-dev"
}
},
"autoload": {
"psr-4": {
"Netcarver\\Textile\\": "src/Netcarver/Textile/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Textile markup language parser",
"homepage": "https://github.com/textile/php-textile",
"keywords": [
"document",
"format",
"html",
"language",
"markup",
"parser",
"php-textile",
"plaintext",
"textile"
],
"support": {
"irc": "irc://irc.freenode.net/textile",
"issues": "https://github.com/textile/php-textile/issues",
"source": "https://github.com/textile/php-textile",
"wiki": "https://github.com/textile/php-textile/wiki"
},
"time": "2020-10-01T18:21:03+00:00"
},
{
"name": "psr/cache",
"version": "1.0.1",
@ -919,12 +907,12 @@
"source": {
"type": "git",
"url": "https://github.com/rybakit/msgpack.php.git",
"reference": "66ca2c3948d72068ca0c8b9a4f599f822a7fe2c3"
"reference": "1e9eda511520e7494c241622671816a83a76e149"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/rybakit/msgpack.php/zipball/66ca2c3948d72068ca0c8b9a4f599f822a7fe2c3",
"reference": "66ca2c3948d72068ca0c8b9a4f599f822a7fe2c3",
"url": "https://api.github.com/repos/rybakit/msgpack.php/zipball/1e9eda511520e7494c241622671816a83a76e149",
"reference": "1e9eda511520e7494c241622671816a83a76e149",
"shasum": ""
},
"require": {
@ -933,7 +921,8 @@
"require-dev": {
"ext-gmp": "*",
"friendsofphp/php-cs-fixer": "^2.14",
"phpunit/phpunit": "^7.1|^8|^9"
"phpunit/phpunit": "^7.1|^8|^9",
"vimeo/psalm": "^3.9|^4"
},
"suggest": {
"ext-decimal": "For converting overflowed integers to Decimal objects",
@ -973,7 +962,7 @@
"type": "github"
}
],
"time": "2021-07-08T19:01:22+00:00"
"time": "2021-12-17T22:02:51+00:00"
},
{
"name": "scssphp/scssphp",
@ -981,12 +970,12 @@
"source": {
"type": "git",
"url": "https://github.com/scssphp/scssphp.git",
"reference": "fd4fc9edc49f5a4465e11e03b7d6198404adbc22"
"reference": "c800975c7408e923309fbb51346b84e83dd05700"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/scssphp/scssphp/zipball/fd4fc9edc49f5a4465e11e03b7d6198404adbc22",
"reference": "fd4fc9edc49f5a4465e11e03b7d6198404adbc22",
"url": "https://api.github.com/repos/scssphp/scssphp/zipball/c800975c7408e923309fbb51346b84e83dd05700",
"reference": "c800975c7408e923309fbb51346b84e83dd05700",
"shasum": ""
},
"require": {
@ -1002,7 +991,7 @@
"symfony/phpunit-bridge": "^5.1",
"thoughtbot/bourbon": "^7.0",
"twbs/bootstrap": "~5.0",
"twbs/bootstrap4": "4.6.0",
"twbs/bootstrap4": "4.6.1",
"zurb/foundation": "~6.5"
},
"suggest": {
@ -1045,11 +1034,11 @@
"issues": "https://github.com/scssphp/scssphp/issues",
"source": "https://github.com/scssphp/scssphp/tree/master"
},
"time": "2021-10-02T12:51:54+00:00"
"time": "2022-01-06T19:41:32+00:00"
},
{
"name": "symfony/polyfill-intl-idn",
"version": "dev-main",
"version": "v1.24.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
@ -1069,7 +1058,6 @@
"suggest": {
"ext-intl": "For best performance"
},
"default-branch": true,
"type": "library",
"extra": {
"branch-alias": {
@ -1117,7 +1105,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-idn/tree/main"
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.24.0"
},
"funding": [
{
@ -1137,7 +1125,7 @@
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "dev-main",
"version": "v1.24.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
@ -1155,7 +1143,6 @@
"suggest": {
"ext-intl": "For best performance"
},
"default-branch": true,
"type": "library",
"extra": {
"branch-alias": {
@ -1202,7 +1189,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.24.0"
},
"funding": [
{
@ -1222,7 +1209,7 @@
},
{
"name": "symfony/polyfill-php72",
"version": "dev-main",
"version": "v1.24.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
@ -1237,7 +1224,6 @@
"require": {
"php": ">=7.1"
},
"default-branch": true,
"type": "library",
"extra": {
"branch-alias": {
@ -1279,7 +1265,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php72/tree/v1.23.0"
"source": "https://github.com/symfony/polyfill-php72/tree/v1.24.0"
},
"funding": [
{
@ -1520,17 +1506,17 @@
"james-heinrich/getid3": 20,
"rybakit/msgpack": 20,
"wapmorgan/binary-stream": 20,
"netcarver/textile": 20,
"al/emoji-detector": 20,
"ezyang/htmlpurifier": 20,
"scssphp/scssphp": 20,
"lfkeitel/phptotp": 20,
"chillerlan/php-qrcode": 20,
"vearutop/php-obscene-censor-rus": 20
"vearutop/php-obscene-censor-rus": 20,
"erusev/parsedown": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.1.0"
"plugin-api-version": "2.0.0"
}

View file

@ -1,4 +1,4 @@
*OpenVK is a universal colleague search tool based on the VKontakte structure.*
**OpenVK is a universal colleague search tool based on the VKontakte structure.**
We want friends, classmates, classmates, neighbors and colleagues to always be in touch.

View file

@ -1,6 +1,6 @@
OpenVK-KB-Heading: Добро пожаловать
*OpenVK - универсальное средство поиска коллег основанное на структуре ВКонтакте.*
**OpenVK - универсальное средство поиска коллег основанное на структуре ВКонтакте.**
Мы хотим, чтобы друзья, однокурсники, одноклассники, соседи и коллеги всегда могли быть в контакте.

View file

@ -1,6 +1,7 @@
OpenVK-KB-Heading: Editing notes
OpenVK wiki-markup is basically XHTML1.0 Transitional. The only difference is that we removed tags that are not needed or may harm OpenVK and it's users.
Allowed tags:
* All headers from level 3 to 6 (h3-h6)
* Paragraphs (&lt;p&gt;)
@ -8,12 +9,13 @@ Allowed tags:
* &lt;sup&gt;, &lt;sub&gt;, &lt;ins&gt;
* Everything related to tables
* Links and images (&lt;a&gt;, &lt;img&gt;)
* Lists (и &lt;ol&gt; и &lt;ul&gt;)
* Lists (and &lt;ol&gt; and &lt;ul&gt;)
* Line feed and horizontal rule (hr)
* Blockquotes (&lt;blockquote&gt; и &lt;cite&gt;)
* Blockquotes (&lt;blockquote&gt; and &lt;cite&gt;)
* &lt;acronym&gt;
*Please note*: images can't have sourcemap and their source must be a file that is hosted on this OpenVK instance. This restrictions does not apply to links. Links can link to everything (except for data: and javascript: pseudoprotocols). They will be derefered though.
**Please note**: images can't have sourcemap and their source must be a file that is hosted on this OpenVK instance. This restrictions does not apply to links. Links can link to everything (except for data: and javascript: pseudoprotocols). They will be derefered though.
You may also have noticed, that &lt;style&gt; is note in the allowlist, however, we do support styling &lt;div&gt; and &lt;img&gt; tags using style attribute. This CSS properties are allowed:
* float
* height
@ -21,4 +23,5 @@ You may also have noticed, that &lt;style&gt; is note in the allowlist, however,
* max-height
* max-width
* font-weight
If property is a size property it can only accept pixels as value (no %, pt, pc, em, rem, vw or vh).

View file

@ -1,6 +1,7 @@
OpenVK-KB-Heading: Справка по редактированию заметок
Вики-разметка OpenVK это тоже самое, что и XHTML1.0 Transitional. Единственное изменение заключается в том, что мы убрали некоторые теги, которые могут принести вред OpenVK или не нужны.
Список разрешённых тегов:
* Все заголовки 3-6 уровней (h3-h6)
* Параграфы (&lt;p&gt;)
@ -12,7 +13,9 @@ OpenVK-KB-Heading: Справка по редактированию замето
* Перевод строки и горизонтальная линия (hr)
* Цитаты (&lt;blockquote&gt; и &lt;cite&gt;)
* &lt;acronym&gt;
Обратите внимание, источником изображения могут быть только файлы из OpenVK. Это ограничение не распространяется на ссылки, где href может быть любой (в целях безопасности наших пользователей, ссылка будет автоматически заменена на редирект через away.php)
Вы могли заметить, что в списке разрешённых тегов нету &lt;style&gt;, но ничего страшного, вы можете применять аттрибут style к тегам &lt;div&gt; и &lt;img&gt;. В перечень поддерживаемых свойств CSS входят:
* float
* height
@ -20,4 +23,5 @@ OpenVK-KB-Heading: Справка по редактированию замето
* max-height
* max-width
* font-weight
Обратите внимание на то, что поддерживаются только значения в пикселях.

View file

@ -1,7 +1,7 @@
OpenVK-KB-Heading: About points
h4. What are points?
#### What are points?
Points are OpenVK internal currency. You can use it to buy stickers and gifts.
h4. How can I buy points?
#### How can I buy points?
This is example knowledgebase article and it does not have the details about this topic. If you are administrator of this social network, please change this article to fit your needs. If you are a user you can ask your admin directly about this.

View file

@ -1,7 +1,7 @@
OpenVK-KB-Heading: Про голоса
h4. Что такое голоса?
#### Что такое голоса?
Голоса это внутреняя валюта OpenVK. За неё можно купить стикеры или подарки другим пользователям.
h4. Как купить голоса?
Это пример статьи о голосах и из-за этого в ней нет таких деталей. Если вы администратор этой социальной сети, отредактируйте файл data/knowledgebase/points.ru.textile, чтобы он соответствовал вашим нуждам. Если вы простой пользователь, уведомите администратора о том, что он забыл отредактировать файлы и спросите у него, как же вам купить голоса.
#### Как купить голоса?
Это пример статьи о голосах и из-за этого в ней нет таких деталей. Если вы администратор этой социальной сети, отредактируйте файл data/knowledgebase/points.ru.md, чтобы он соответствовал вашим нуждам. Если вы простой пользователь, уведомите администратора о том, что он забыл отредактировать файлы и спросите у него, как же вам купить голоса.

View file

@ -1,31 +1,31 @@
OpenVK-KB-Heading: Privacy Policy
h2. What information do we collect?
## What information do we collect?
* _Basic account information_: If you register on this server, you may be asked to enter your real name, last name, an email address, and a password. You may also enter additional profile information such as a nickname, status, biography, interests, etc. Your first name, last name, a nickname, a status, and a profile picture are always listed publicly.
* _Posts, private messages and other information_: All information is processed and stored on the server. When you submit any content, the date and time are stored with the post, including attachments. Messages may contain media attachments, such as pictures and videos. Posts are available publicly. Personal messages are only delivered to users to whom you have personally sent messages. _Please do not share any dangerous information over OpenVK._
* _IPs and other metadata_: When you log in, we may record the IP address you log in from, as well as the name of your browser application. We also may retain server logs which include the IP address of every request to our server.
h2. What do we use your information for?
## What do we use your information for?
Any of the information we collect from you may be used in the following ways:
* To provide the core functionality of OpenVK. You can only interact with other people's content and post your own content when you are logged in.
* To aid moderation of the community, for example comparing your IP address with other known ones to determine ban evasion or other violations.
* The email address you provide may be used to regain access to your account by changing your password.
h2. How do we protect your information?
## How do we protect your information?
We implement a variety of security measures to maintain the safety of your personal information when you enter, submit, or access your personal information. Among other things, your browser session, as well as the traffic between your applications and the API, are secured with SSL, and your password is hashed using a strong one-way algorithm.
h2. Do we use cookies?
## Do we use cookies?
Yes. Cookies are small files that a site or its service provider transfers to your computer's hard drive through your Web browser (if you allow). These cookies enable the site to recognize your browser and, if you have a registered account, associate it with your registered account.
We use cookies to understand and save your preferences for future visits.
h2. Do we disclose any information to outside parties?
## Do we disclose any information to outside parties?
We do not sell, trade, or otherwise transfer to outside parties your personally identifiable information. This does not include trusted third parties who assist us in operating our site, or servicing you, so long as those parties agree to keep this information confidential. We may also release your information when we believe release is appropriate to comply with the law, enforce our site policies, or protect ours or others rights, property, or safety.
h2. Changes to our Privacy Policy
## Changes to our Privacy Policy
If we decide to change our privacy policy, we will post those changes on this page.
This document is CC-BY-SA. It was last updated October 8, 2021.
Originally adapted from the "Mastodon privacy policy":https://mastodon.social/terms.
Originally adapted from the [Mastodon privacy policy](https://mastodon.social/terms).

View file

@ -1,31 +1,31 @@
OpenVK-KB-Heading: Политика Конфиденциальности
h2. Какую информацию мы собираем?
## Какую информацию мы собираем?
* _Основная информация_: Если у вас есть желание зарегистрироваться на данном сайте, вас могут попросить ввести реальное имя, фамилию, адрес электронной почты и пароль. Также вы можете ввести дополнительную информацию профиля, например, псевдоним, статус, биографию, интересы, и т.д. Имя, фамилия, псевдоним, статус и фото профиля будут общедоступными.
* _Записи, личные сообщения и другая информация_: Вся информация обрабатывается и хранится на сервере. Когда вы отправляете любой контент, дата и время сохраняются с записью, включая вложения. Сообщения могут включать медиа вложения, к примеру изображения и видео. Записи являются общедоступной информацией. Личные сообщения доставляются только тем пользователями, которым Вы лично отправили сообщения. _Пожалуйста, не делитесь любой вредоносной информации через OpenVK._
* _IP-адреса и другие метаданные_: Когда Вы выполняете вход в свой аккаунт, мы можем записывать IP-адрес, с которого был произведён вход, и название вашего веб-браузера. Мы также можем сохранять журналы сервера, которые включают IP-адрес каждого запроса к серверу.
h2. Для чего мы используем вашу информацию?
## Для чего мы используем вашу информацию?
Любую собранную нами информацию мы используем для следующих целей:
* Для предоставления базового функционала OpenVK. Вы можете взаимодействовать с чужим контентом и размещать собственный контент только тогда, когда Вы вошли в систему.
* Чтобы помочь модерации сообщества, например, сравнить ваш IP-адрес с другими известными адресами, чтобы определить уклонения от блокировки или других нарушений.
* Предоставленный вами адрес электронной почты может быть использован для восстановления доступа к вашему аккаунту при помощи смены пароля.
h2. Как мы защищаем вашу информацию?
## Как мы защищаем вашу информацию?
Мы применяем различные меры безопасности для обеспечения сохранности вашей личной информации, когда вы вводите, отправляете или получаете доступ к своей личной информации. Среди прочего, сессия вашего браузера, а также трафик между вашими приложениями и API защищены протоколом SSL, а ваш пароль хэшируется с помощью надежного одностороннего алгоритма.
h2. Используем ли мы файлы cookies?
## Используем ли мы файлы cookies?
Да. Cookies - это небольшие файлы, которые сайт или его поставщик услуг передает на жесткий диск вашего компьютера через ваш веб-браузер (если вы разрешаете). Эти файлы cookie позволяют сайту распознать ваш браузер и, если у вас есть зарегистрированная учетная запись, связать ее с вашей зарегистрированной учетной записью.
Мы используем файлы cookies, чтобы понять и сохранить ваши настройки для будущих посещений.
h2. Раскрываем ли мы какую-либо информацию сторонним лицам?
## Раскрываем ли мы какую-либо информацию сторонним лицам?
Мы не продаем, не обмениваем и не передаем посторонним лицам вашу личную информацию. Это не относится к доверенным третьим лицам, которые помогают нам управлять нашим сайтом или обслуживать вас, если эти лица согласны сохранять конфиденциальность этой информации. Мы также можем раскрыть вашу информацию, если считаем, что это необходимо для соблюдения закона, исполнения правил нашего сайта или защиты наших или чужих прав, собственности или безопасности.
h2. Изменения в нашей Политике конфиденциальности
## Изменения в нашей Политике конфиденциальности
Если мы решим изменить нашу политику конфиденциальности, мы опубликуем эти изменения на данной странице.
Данный документ лицензирован по CC-BY-SA. В последний раз обновлялся 8 октября 2021.
Первоначально адаптировано из "Политики конфиденциальности Mastodon":https://mastodon.social/terms.
Первоначально адаптировано из [Политики конфиденциальности Mastodon](https://mastodon.social/terms).

View file

@ -0,0 +1,44 @@
OpenVK-KB-Heading: Rules
The site administration allows you to use the site on the terms specified in these rules.
You can do everything that does not apply to prohibited actions, but they include:
1. Refusing to obey the rules or ignoring them,
2. Waiver of the mandatory presence of representatives of tech support agents or administration,
3. Using other people's pages without the permission of the owner,
4. Impersonating other people for gain. Exceptions:
1. The person has allowed the use of his identity,
2. The person is an original character belonging to you
5. Creation of mass mailings in any way,
6. Creating situations that in any way interfere with the operation of OpenVK,
7. The publication and storage on the resource of any content that:
1. Is illegal in France or your country of residence,
2. Contains pornographic scenes involving persons under the age of 18,
3. Contains advertisements for drugs banned in France or your country of residence or instructions for their preparation,
4. Contains information prohibited in France or your country of residence,
5. Contains scenes of inhuman treatment of people or animals,
6. Violates copyright and related rights,
7. Violates human rights
8. Prevents users from following the rules or from properly using the services provided by the OpenVK project.
The administration is the highest authority that has the full right to make decisions about disputes that are not described in the rules.
The administration may issue a punishment if users:
1. Post prohibited content on the pages of other users,
2. They deceive the administration or tech support agents,
3. Mislead website users,
4. Publicly criticize OpenVK or the administration in order to humiliate or insult project participants or its leaders
5. Banned from official OpenVK chats on Telegram,
6. They do not respect the Project administration or tech support agents.
In case of violation of the rules, the administration can:
1. Ignore a violation that is minor,
2. Issue a warning to the user
3. Issue a temporary or permanent ban,
4. Prohibit future use of this site,
5. Remove account or prohibited content.
The administration can issue punishments without giving a reason (even if there is one).

View file

@ -0,0 +1,44 @@
OpenVK-KB-Heading: Правила
Администрация сайта разрешает Вам пользоваться сайтом на условиях, которые определены в этих правилах.
Делать можно всё то, что не относится к запрещённым действиям, а к ним относятся:
1. Отказ от подчинения правилам или их игнорирование,
2. Отказ от своевременного исполнения запросов агентов тех. поддержки или администрации,
3. Использование чужих страниц без разрешения владельца,
4. Выдача себя за других людей для получения выгоды. Исключения:
1. Человек разрешил использование своей личности,
2. Человек является оригинальным персонажем, принадлежащим Вам
5. Создание массовых рассылок любым способом,
6. Создание ситуаций, любым образом мешающих работе OpenVK,
7. Публикация и хранение на ресурсе любого содержимого, которое:
1. Является незаконным на территории Франции или Вашей страны проживания,
2. Содержит порнографические сцены с участием лиц младше 18 лет,
3. Содержит рекламу запрещенных в Франции или Вашей стране проживания препаратов или инструкции по их приготовлению,
4. Содержит информацию, запрещённую на территории Франции или Вашей страны проживания,
5. Содержит сцены бесчеловечного обращения с людьми или животными,
6. Нарушает авторские и смежные права,
7. Нарушает права человека,
8. Мешает пользователям исполнять правила или нормально пользоваться услугами, предоставляемыми проектом OpenVK.
Администрация является высшим органом власти, имеющим полное право принимать решения насчёт спорных ситуаций, не описанных в правилах.
Администрация может выдать наказание, если пользователи:
1. Публикуют запрещённый контент на страницах других пользователей,
2. Обманывают администрацию или агентов тех. поддержки,
3. Вводят в заблуждение пользователей сайта,
4. Публично критикуют OpenVK или администрацию с целью унизить или оскорбить участников проекта или его руководителей,
5. Забанены в официальных чатах OpenVK в Telegram,
6. Не уважают администрацию проекта или агентов тех. поддержки.
При нарушении правил, администрация может:
1. Проигнорировать нарушение, являющееся незначительным,
2. Вынести пользователю предупреждение,
3. Выдать временную или постоянную блокировку,
4. Запретить в будущем пользоваться этим сайтом,
5. Удалить аккаунт или запрещенный контент.
Администрация может выдавать наказания без объяснения причины (даже если таковая имеется).

View file

@ -1,58 +0,0 @@
OpenVK-KB-Heading: Правила
Добро пожаловать на *инстанцию OpenVK* имени Веселкрафта. OpenVK -- социальная сеть с открытым исходным кодом, которая помогает людям поддерживать связь со своими друзьями и заводить новых.
Администрация этой инстанции разрешает вам пользоваться ею на условиях, которые определены в этом документе (далее по тексту - правила).
h3. Статус этих правил
Эти правила являются черновиком. Мы их ещё дорабатываем и приниманием предложения от пользователей. Но не смотря на это, эти правила всё равно действуют и к Вам могут быть применены санкции из-за их нарушения.
Эти правила могут изменяться без уведомления. Продолжение использования инстанции OpenVK будет означать согласие с ними.
h3. Область действия этих правил
Эти правила распостраняются только на эту инстанцию OpenVK, а именно на всё, что расположено на домене openvk2.veselcraft.ru (включая все его поддомены).
За пределами этой инстанции правила не действуют и Вы в праве делать всё, что посчитаете нужным.
h3. Что можно делать?
Делать можно всё, что не запрещено. А запрещено:
# Не следовать правилам
# Не отвечать своевременно на запросы от техподдержки или Администрации
# Выдавать себя за других людей
## Если это не было разрешено явно другим человеком
## Если другой человек на самом деле оригинальный персонаж, который принадлежит Вам
## Также нельзя заходить на чужие страницы без разрешения (взлом жопы)
# Делать массовые рассылки любым способом
# Мешать любым образом работе OpenVK
# Загружать на сайт и с сайта любым образом любое содержимое, которое:
## Не является законным на територии Нидерландов и Вашей страны проживания:
### Содержит порнографию с участием несовершеннолетних лиц
#### Если эти лица не являются вымышленными персонажами
### Содержит рекламу наркотических препаратов или инструкции по их приготовлению
### Содержит информацию закрытого доступа
### Содержит сцены бесчеловечного обращения с животными
### Нарушает авторские и смежные права
### Нарушает права человека
## Содержит спойлеры
## Мешает другим пользователям исполнять правила
## Мешает другим пользователям нормально пользоваться OpenVK
## Администрация может посчитать недопустимым
# Загружать "adult"-контент на страницах других пользователей без разрешения
# Обманывать Администрацию и/или _неопределённую_ группу пользователей
## Неопределённа группа пользователей -- пользователи, которых вы не знаете. Обманывать своих друзей можно.
# Оскорблять OpenVK и/или Администрацию
## Если это не оправданно
# Быть забаненным в OpenVK Chat, /KDE/ или в чате, который располагается по имени traintovos
# Не уважать Веселкрафта, Косфурлера и Джилл
h3. Санкции за нарушение правил
За нарушение этих правил, мы можем:
# Проигнорировать нарушение
# Вынести Вам устное предуреждение
# Выдать временную или постоянную блокировку
# Запретить Вам в будущем пользоваться этой инстанцией
# Удалить Ваш контент и/или аккаунт
Определение наказания и его последующее исполнение - обязанность Администрации.
Также мы оставляем за собой право применить санкции к Вам не объясняя причин (если они вообще будут).

View file

@ -1,3 +0,0 @@
OpenVK-KB-Heading: Rules
Sample rules

View file

@ -1 +0,0 @@
Sample rules

View file

@ -1,357 +0,0 @@
# Installing OpenVK
Based on [@rem-pai](https://github.com/rem-pai)'s way to install OpenVK modified using my experience.
!!WARNING!!
CentOS 8 is reaching it's end-of-life soon. There are other supported similar distributions like Rocky Linux or AlmaLinux.
## SELinux
🖥Run the command:
```bash
sestatus
```
If it says `SELinux status: enabled` then SELinux will disturb us. Let's disable it.
_Note: I know that it's not most secured solution but I don't know any proper way that will work._
📝Edit file `/etc/sysconfig/selinux` and change the line `SELinux=enforcing` to `SELinux=disabled`, then 🔌reboot your machine. `sestatus` should tell `SELinux status: disabled` right now.
## Dependencies
🖥Let's install EPEL and Remi repos for PHP 7.4:
```bash
dnf -y install epel-release
dnf -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm
```
🖥Then enable modules that we need:
```bash
dnf -y module enable php:remi-7.4
dnf -y module enable nodejs:14
```
🖥And install dependencies:
```bash
dnf -y install php php-cli php-common unzip php-zip php-yaml php-gd php-pdo_mysql nodejs git
```
🖥Don't forget about Yarn and Composer:
```bash
npm i -g yarn
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php --filename=composer2 --install-dir=/bin --snapshot
rm composer-setup.php
```
### Database
🖥We will use Percona Server for DB:
```bash
dnf -y install https://repo.percona.com/yum/percona-release-latest.noarch.rpm
percona-release setup -y ps80
dnf -y install percona-server-server percona-toolkit
systemctl start mysql
```
🖥And then look up for temporary password:
```bash
cat /var/log/mysqld.log | grep password
```
It should look like this:
2021-01-11T12:56:09.203991Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: >b?Q.fDXJ4fk
🖥Then run `mysql_secure_installation`, set new password and answer like this:
Change the password for root ? ((Press y|Y for Yes, any other key for No) : n
Remove anonymous users? (Press y|Y for Yes, any other key for No) : y
Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y
Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
### ffmpeg
Additionally, you can install ffmpeg for processing videos.
🖥You will need to use RPMFusion repo to install it:
```bash
dnf -y localinstall --nogpgcheck https://download1.rpmfusion.org/free/el/rpmfusion-free-release-8.noarch.rpm
dnf -y install --nogpgcheck https://download1.rpmfusion.org/free/el/rpmfusion-free-release-8.noarch.rpm
```
🖥Then install SDL2 and ffmpeg:
```bash
dnf -y install http://rpmfind.net/linux/epel/7/x86_64/Packages/s/SDL2-2.0.10-1.el7.x86_64.rpm
dnf -y install ffmpeg
```
## Chandler and OpenVK installation
🖥Install Chandler in `/opt`:
```bash
cd /opt
git clone https://github.com/openvk/chandler.git
cd chandler/
composer2 install
```
🖥You will need a secret key. You can generate it using:
```bash
cat /dev/random | tr -dc 'a-z0-9' | fold -w 128 | head -n 1
```
📝Now edit config file `chandler-example.yml` like this:
```yaml
chandler:
debug: true
websiteUrl: null
rootApp: "openvk"
preferences:
appendExtension: "xhtml"
adminUrl: "/chandlerd"
exposeChandler: true
database:
dsn: "mysql:unix_socket=/var/lib/mysql/mysql.sock;dbname=db"
user: "root"
password: "DATABASE_PASSWORD"
security:
secret: "SECRET_KEY_HERE"
csrfProtection: "permissive"
sessionDuration: 14
```
🖥And rename it to `chandler.yml`:
```bash
mv chandler-example.yml chandler.yml
```
🖥Now let's install CommitCaptcha extension. It is mandatory for OpenVK.
```bash
cd extensions/available/
git clone https://github.com/openvk/commitcaptcha.git
cd commitcaptcha/
composer2 install
```
🖥And now download OpenVK:
```bash
cd ..
git clone https://github.com/openvk/openvk.git
cd openvk/
composer2 install
cd Web/static/js
yarn install
```
📝Now edit config file `openvk-example.yml` like this:
```yaml
openvk:
debug: true
appearance:
name: "OpenVK"
motd: "Yet another OpenVK instance"
preferences:
femaleGenderPriority: true
uploads:
disableLargeUploads: false
mode: "basic"
shortcodes:
forbiddenNames:
- "index.php"
security:
requireEmail: false
requirePhone: false
forcePhoneVerification: false
forceEmailVerification: false
enableSu: true
rateLimits:
actions: 5
time: 20
maxViolations: 50
maxViolationsAge: 120
autoban: true
support:
supportName: "Moderator"
adminAccount: 1 # Change this ok
messages:
strict: false
wall:
postSizes:
maxSize: 60000
processingLimit: 3000
emojiProcessingLimit: 1000
menu:
links:
adPoster:
enable: false
src: "https://example.org/ad_poster.jpeg"
caption: "Ad caption"
link: "https://example.org/product.aspx?id=10&from=ovk"
bellsAndWhistles:
fartscroll: false
testLabel: false
credentials:
smsc:
enable: false
client: ""
secret: ""
eventDB:
enable: true # Better enable this
database:
dsn: "mysql:unix_socket=/var/lib/mysql/mysql.sock;dbname=openvk_eventdb"
user: "root"
password: "DATABASE_PASSWORD"
```
Please note `eventDB` section because it's better to enable event database.
🖥And rename it to `openvk.yml`:
```bash
mv openvk-example.yml openvk.yml
```
🖥Then enable CommitCaptcha and OpenVK for Chandler:
```bash
ln -s /opt/chandler/extensions/available/commitcaptcha/ /opt/chandler/extensions/enabled/commitcaptcha
ln -s /opt/chandler/extensions/available/openvk/ /opt/chandler/extensions/enabled/openvk
```
### DB configuration
_Note: it's better to create another user for SQL but I won't cover that._
🖥Enter MySQL shell:
```bash
mysql -p
```
🖥And create main and event databases:
```sql
CREATE DATABASE openvk;
CREATE DATABASE openvk_eventdb;
exit
```
🖥Go to `/opt/chandler`:
```bash
cd /opt/chandler
```
📝We need to import Chandler database but for some reason it's not ready for use so we need to edit dump `install/init-db.sql`:
1\. Remove ` PAGE_CHECKSUM=1` everywhere.
2\. Replace `Aria` with `InnoDB` everywhere.
🖥Now database dump can be imported:
```bash
mysql -p'DATABASE_PASSWORD' openvk < install/init-db.sql
```
🖥Go to `extensions/available/openvk/`:
```bash
cd extensions/available/openvk/
```
📝We also need to import OpenVK database. Unless you use MariaDB (we are using Percona here) you should edit `install/init-static-db.sql`:
1\. Replace `utf8mb4_unicode_nopad_ci` with `utf8mb4_unicode_520_ci` everywhere.
🖥Now database dump can be imported:
```bash
mysql -p'DATABASE_PASSWORD' openvk < install/init-static-db.sql
```
🖥Also import event database:
```bash
mysql -p'DATABASE_PASSWORD' openvk_eventdb < install/init-event-db.sql
```
### Webserver configuration
Apache is already installed so we will use it.
🖥Make the user `apache` owner of the `chandler` folder:
```bash
cd /opt
chown -R apache: chandler/
```
📝Now let's create config file `/etc/httpd/conf.d/10-openvk.conf`:
```apache
<VirtualHost *:80>
ServerName openvk.local
DocumentRoot /opt/chandler/htdocs
<Directory /opt/chandler/htdocs>
AllowOverride All
Require all granted
</Directory>
ErrorLog /var/log/openvk/error.log
CustomLog /var/log/openvk/access.log combinedio
</VirtualHost>
```
📝Also enable rewrite_module by creating `/etc/httpd/conf.modules.d/02-rewrite.conf`:
```apache
LoadModule rewrite_module modules/mod_rewrite.so
```
🖥Make directory for OpenVK logs and make the user `apache` owner of it:
```bash
mkdir /var/log/openvk
chown apache: /var/log/openvk/
```
🖥Make the firewall exception for port 80:
```bash
firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --reload
```
🖥And start Apache:
```bash
systemctl start httpd
```
OpenVK should work right now!
Also you can raise 2MB the file limit through editing `/etc/php.ini`. And it's also better to install PHPMyAdmin but I won't cover that.

View file

@ -1 +1,3 @@
--- if you haven't used helpdesk before nov 25, 2021 - you will not need it.
UPDATE `tickets_comments` SET `text`=REGEXP_REPLACE(`text`, "(?:Здравствуйте, [^!]*!<br><\/br>|<br><\/br>С уважением,<br\/> Команда поддержки OpenVK.)", "") WHERE 1=1;

View file

@ -0,0 +1,9 @@
ALTER TABLE `profiles` ADD `activated` tinyint(3) NULL DEFAULT '1' AFTER `2fa_secret`;
CREATE TABLE IF NOT EXISTS `email_verifications` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`profile` bigint(20) unsigned NOT NULL,
`key` char(64) COLLATE utf8mb4_general_nopad_ci NOT NULL,
`timestamp` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_nopad_ci;

View file

@ -1,5 +1,5 @@
# Locales for OpenVK
So, there is a locales contained here for [OpenVK](../../../openvk).
So, there is a locales contained here for [OpenVK](../../../).
## Contributing

View file

@ -6,6 +6,7 @@
"home" = "Home";
"welcome" = "Welcome";
"to_top" = "To top";
/* Login */
@ -34,6 +35,13 @@
"password_reset_error" = "An unexpected error occurred while resetting the password.";
"password_reset_rate_limit_error" = "You can't do it that often, sorry.";
"email_sent" = "Mail has been successfully sent.";
"email_sent_desc" = "If your email addess exists, you will receive instructions.";
"email_error" = "An unexpected error occurred while sending the email.";
"email_rate_limit_error" = "You can't do it that often, sorry.";
"email_verify_success" = "Your Email has been verified. Have a great time!";
"registration_disabled_info" = "Registration has been disabled by the system administrator. If possible, ask for an invitation from your friend, if he is registered on this site.";
"registration_closed" = "Registration is closed.";
"invites_you_to" = "<strong>$1</strong> invites you to $2";
@ -215,6 +223,7 @@
"subscriptions" = "Subscriptions";
"join_community" = "Join community";
"leave_community" = "Leave community";
"check_community" = "View community";
"min_6_community" = "Name of the group must have more that 6 characters";
"participants" = "Participants";
"groups" = "Groups";
@ -232,6 +241,7 @@
"only_administrators" = "Only administrators";
"website" = "Website";
"managed" = "Managed";
"size" = "Size";
"administrators_one" = "$1 administrator";
"administrators_other" = "$1 administrators";
@ -264,10 +274,20 @@
"groups_one" = "$1 group";
"groups_other" = "$1 groups";
"groups_list_zero" = "You are not a participant in any group";
"groups_list_one" = "You are participating in one group";
"groups_list_other" = "You are a participant of $1 groups";
"meetings_zero" = "No meetings";
"meetings_one" = "$1 meeting";
"meetings_other" = "$1 meetings";
"open_new_group" = "Open a new group";
"open_group_desc" = "Can't find the right group? Open your own...";
"search_group" = "Search group";
"search_by_groups" = "Search by groups";
"search_group_desc" = "Here you can browse through the existing groups and choose a group to suit your needs...";
/* Albums */
"create" = "Create";
@ -295,8 +315,11 @@
"name_note" = "Title";
"text_note" = "Content";
"create_note" = "Create note";
"edit_note" = "Edit note";
"actions" = "Actions";
"edited" = "Edited";
"notes_zero" = "No notes";
"notes_one" = "$1 note";
"notes_other" = "$1 notes";
@ -369,6 +392,8 @@
"cut" = "Cut";
"round_avatars" = "Round avatars";
"apply_style_for_this_device" = "Apply style only for this device";
"search_for_groups" = "Search for groups";
"search_for_people" = "Search for people";
"search_button" = "Find";
@ -647,6 +672,14 @@
"banned_2" = "And the reason for this is simple: <b>$1</b>. Unfortunately, this time we had to block you forever.";
"banned_3" = "You can still <a href=\"/support?act=new\">write to the support</a> if you think there was an error or <a href=\"/logout?hash=$1\">logout</a>.";
/* Registration confirm */
"ec_header" = "Registration confirmation";
"ec_title" = "Thanks!";
"ec_1" = "<b>$1</b>, your registration is almost done. In a few minutes you should receive an mail with a link to confirm your email address.";
"ec_2" = "If for some reason you don't get the mail, check your spam folder. If you don't find the email there, you can resend it.";
"ec_resend" = "Resend mail";
/* Discussions */
"discussions" = "Discussions";

View file

@ -69,3 +69,13 @@ list:
name: "Esperanto"
native_name: "Esperanto"
author: "n1rwana"
- code: "su"
flag: "su"
name: "Soviet"
native_name: "Советский"
author: "mohooks"
- code: "udm"
flag: "udm"
name: "Udmurtskiy"
native_name: "Удмуртский"
author: "mohooks"

View file

@ -7,6 +7,7 @@
"home" = "Главная";
"welcome" = "Добро пожаловать";
"to_top" = "Вверх";
/* Login */
@ -35,6 +36,13 @@
"password_reset_error" = "Непредвиденная ошибка при сбросе пароля.";
"password_reset_rate_limit_error" = "Нельзя делать это так часто, извините.";
"email_sent" = "Письмо было успешно отправлено.";
"email_sent_desc" = "Если ваш электронный адрес существует, вы получите письмо.";
"email_error" = "Непредвиденная ошибка при отправке письма.";
"email_rate_limit_error" = "Нельзя делать это так часто, извините.";
"email_verify_success" = "Ваш Email был подтверждён. Приятного времяпрепровождения!";
"registration_disabled_info" = "Регистрация отключена системным администратором. При возможности попросите приглашение у вашего знакомого, если он зарегистрирован на этом сайте.";
"registration_closed" = "Регистрация закрыта.";
"invites_you_to" = "<strong>$1</strong> приглашает вас в $2";
@ -224,6 +232,7 @@
"subscriptions" = "Подписки";
"join_community" = "Вступить в группу";
"leave_community" = "Выйти из группы";
"check_community" = "Просмотр группы";
"min_6_community" = "Название должно быть не менее 6 символов";
"participants" = "Участники";
"groups" = "Группы";
@ -241,6 +250,7 @@
"only_administrators" = "Только администраторы";
"website" = "Сайт";
"managed" = "Управляемые";
"size" = "Размер";
"administrators_one" = "$1 администратор";
"administrators_few" = "$1 администратора";
@ -278,12 +288,22 @@
"groups_many" = "$1 групп";
"groups_other" = "$1 групп";
"groups_list_zero" = "Вы не состоите ни в одной группе";
"groups_list_one" = "Вы состоите в одной группе";
"groups_list_other" = "Вы состоите в $1 группах";
"meetings_zero" = "Ни одной встречи";
"meetings_one" = "Одна встреча";
"meetings_few" = "$1 встречи";
"meetings_many" = "$1 встреч";
"meetings_other" = "$1 встреч";
"open_new_group" = "Открыть новую группу";
"open_group_desc" = "Не можете найти нужную группу? Откройте свою...";
"search_group" = "Поиск группы";
"search_by_groups" = "Поиск по группам";
"search_group_desc" = "Здесь Вы можете просмотреть существующие группы и выбрать группу себе по вкусу...";
/* Albums */
"create" = "Создать";
@ -313,8 +333,11 @@
"name_note" = "Название";
"text_note" = "Содержание";
"create_note" = "Создать заметку";
"edit_note" = "Редактировать заметку";
"actions" = "Действия";
"edited" = "Отредактировано";
"notes_zero" = "Ни одной заметки";
"notes_one" = "Одна заметка";
"notes_few" = "$1 заметки";
@ -387,6 +410,8 @@
"cut" = "Обрезка";
"round_avatars" = "Круглый аватар";
"apply_style_for_this_device" = "Применить стиль только для этого устройства";
"search_for_groups" = "Поиск групп";
"search_for_people" = "Поиск людей";
"search_button" = "Найти";
@ -676,6 +701,14 @@
"banned_2" = "А причина этому проста: <b>$1</b>. К сожалению, на этот раз нам пришлось заблокировать вас навсегда.";
"banned_3" = "Вы всё ещё можете <a href=\"/support?act=new\">написать в службу поддержки</a>, если считаете что произошла ошибка или <a href=\"/logout?hash=$1\">выйти</a>.";
/* Registration confirm */
"ec_header" = "Подтверждение регистрации";
"ec_title" = "Спасибо!";
"ec_1" = "<b>$1</b>, ваша регистрация почти закончена. В течении нескольких минут на ваш адрес E-mail должно прийти письмо с ссылкой для подтверждения вашего адреса почты.";
"ec_2" = "Если по каким-то причинам вам не пришло письмо, то проверьте папку Спам. Если письма не окажется и там, то вы можете переотправить письмо.";
"ec_resend" = "Переотправить письмо";
/* Discussions */
"discussions" = "Обсуждения";
@ -848,4 +881,4 @@
/* User alerts */
"user_alert_scam" = "На этот аккаунт много жаловались в связи с мошенничеством. Пожалуйста, будьте осторожны, особенно если у вас попросят денег.";
"user_alert_scam" = "На этот аккаунт много жаловались в связи с мошенничеством. Пожалуйста, будьте осторожны, особенно если у вас попросят денег.";

814
locales/su.strings Normal file
View file

@ -0,0 +1,814 @@
"__locale" = "su_SU.utf8;su_SU.UTF-8;Rus";
"__WinEncoding" = "Windows-1251";
/* Check for https://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html */
/* Main page */
"home" = "Главная";
"welcome" = "Добро пожаловать";
/* Login */
"log_in" = "Вход";
"password" = "Пароль";
"registration" = "Регистрация";
"forgot_password" = "Забыли пароль?";
"login_failed" = "Не удалось войти";
"invalid_username_or_password" = "Неверное имя пользователя или пароль. <a href='/restore.pl'>Забыли пароль?</a>";
"failed_to_register" = "Не удалось зарегистрироваться";
"referral_link_invalid" = "Пригласительная ссылка недействительна.";
"registration_disabled" = "Регистрация отключена системным администратором.";
"user_already_exists" = "Пользователь с таким email уже существует.";
"access_recovery" = "Восстановление доступа";
"page_access_recovery" = "Восстановить доступ к странице";
"access_recovery_info" = "Забыли пароль? Не волнуйтесь, введите ваши данные и мы отправим вам email с инструкциями по восстановлению аккаунта.";
"access_recovery_info_2" = "Введите ваш новый пароль. Все текущие сеансы будут приостановлены и токены доступа будут аннулированы.";
"reset_password" = "Сбросить пароль";
"2fa_code_2" = "Код двухфакторной аутентификации";
"password_successfully_reset" = "Ваш пароль был успешно сброшен.";
"password_reset_email_sent" = "Если вы зарегистрированы, вы получите инструкции на email.";
"password_reset_error" = "Непредвиденная ошибка при сбросе пароля.";
"password_reset_rate_limit_error" = "Нельзя делать это так часто, извините.";
"registration_disabled_info" = "Регистрация отключена системным администратором. При возможности попросите приглашение у вашего знакомого, если он зарегистрирован на этом сайте.";
"registration_closed" = "Регистрация закрыта.";
"invites_you_to" = "<strong>$1</strong> приглашает вас в $2";
"register_meta_desc" = "Зарегистрируйтесь в $1 прямо сейчас!";
"register_referer_meta_title" = "$1 приглашает вас в $2!";
"register_referer_meta_desc" = "Присоединяйтесь к $1 и множеству других пользователей в $2!";
"users" = "Пользователи";
/* Profile information */
"select_language" = "Выбрать язык";
"edit" = "Изменить";
"birth_date" = "День рождения";
"registration_date" = "Дата регистрации";
"hometown" = "Родной город";
"this_is_you" = "это Вы";
"edit_page" = "Изменить информацию досье";
"edit_group" = "Изменить информацию клуба";
"change_status" = "изменить ";
"name" = "Имя";
"surname" = "Фамилия";
"gender" = "Пол";
"male" = "мужской";
"female" = "женский";
"description" = "Описание";
"save" = "Сохранить";
"main_information" = "Основная информация";
"nickname" = "Прозвище";
"online" = "Онлайн";
"was_online" = "заходил в орган";
"was_online_m" = "заходил в орган";
"was_online_f" = "заходила в орган";
"all_title" = "Все";
"information" = "Информация";
"status" = "Статус";
"no_information_provided" = "Информация отсутствует.";
"deceased_person" = "Страница покойного человека";
"none" = "отсутствует";
"send" = "Отправить";
"years_zero" = "0 лет";
"years_one" = "1 год";
"years_few" = "$1 года";
"years_many" = "$1 лет";
"years_other" = "$1 лет";
"relationship" = "Семейное положение";
"relationship_0" = "Не выбрано";
"relationship_1" = "Не женат";
"relationship_2" = "Встречаюсь";
"relationship_3" = "Помолвлен";
"relationship_4" = "Женат";
"relationship_5" = "В гражданском браке";
"relationship_6" = "Влюблен";
"relationship_7" = "Всё сложно";
"relationship_8" = "В активном поиске";
"politViews" = "Полит. взгляды";
"politViews_0" = "Не выбраны";
"politViews_1" = "Индифферентные";
"politViews_2" = "Коммунистические";
"politViews_3" = "Социалистические";
"politViews_4" = "Умеренные";
"politViews_5" = "Либеральные";
"politViews_6" = "Консервативные";
"politViews_7" = "Монархические";
"politViews_8" = "Ультраконсервативные";
"politViews_9" = "Либертарианские";
"contact_information" = "Контактная информация";
"email" = "Почтовый ящик";
"phone" = "Телефон";
"telegram" = "Telegram";
"personal_website" = "Личная визитка";
"city" = "Город";
"address" = "Адрес";
"personal_information" = "Личная информация";
"interests" = "Интересы";
"favorite_music" = "Любимые аудиозаписи";
"favorite_films" = "Любимые киноленты";
"favorite_shows" = "Любимые программы";
"favorite_books" = "Любимые книги";
"favorite_quotes" = "Любимые цитаты";
"information_about" = "О себе";
"updated_at" = "Обновлено $1";
"user_banned" = "Органу управления пришлось отправить <b>$1</b> под стражу.";
"user_banned_comment" = "Комментарий милиции:";
/* Wall */
"feed" = "Новостная газета";
"post_writes_m" = "написал";
"post_writes_f" = "написала";
"post_writes_g" = "опубликовали";
"wall" = "Доска";
"post" = "Запись";
"write" = "Написать";
"publish" = "Опубликовать";
"delete" = "Удалить";
"comments" = "Отзывы";
"share" = "Поделиться";
"pin" = "Закрепить";
"unpin" = "Открепить";
"pinned" = "закреплено";
"comments_tip" = "Гражданин, будьте первым, кто напишет отзыв!";
"your_comment" = "Ваш отзыв";
"shown" = "Показано";
"x_out_of" = "$1 из";
"wall_zero" = "нет записей";
"wall_one" = "единственная запись";
"wall_few" = "$1 записи";
"wall_many" = "$1 записей";
"wall_other" = "$1 записей";
"publish_post" = "Добавить запись";
"view_other_comments" = "Посмотреть остальные комментарии";
"no_comments" = "Отзывы отсутствуют";
"all_news" = "Все новостные газеты";
"posts_per_page" = "Количество записей в досье";
"attachment" = "Вложение";
"post_as_group" = "От имени клуба";
"comment_as_group" = "От имени клуба";
"add_signature" = "Подпись участника клуба";
"contains_nsfw" = "Содержит запрещённый контент";
"nsfw_warning" = "Товарищ, данная запись не прошла цензуру органом записи, мы не рекомендуем данную запись просматривать.";
"report" = "Пожаловаться";
"attach" = "Прикрепить";
"attach_photo" = "Прикрепить картинку";
"attach_video" = "Прикрепить киноленту";
"draw_graffiti" = "Нарисовать иллюстрацию";
"no_posts_abstract" = "Товарищ, здесь пока никто ничего не оставил.";
"attach_no_longer_available" = "Этот материал больше не подлежит к просмотру.";
"open_post" = "Открыть запись";
"version_incompatibility" = "Товарищ, органу управления не удалось достать из библиотеки данный материал. Возможно, он был порван или бибилотека не совместима с версией OpenVK";
"reply" = "Ответить";
/* Friends */
"friends" = "Товарищи";
"followers" = "Подписчики";
"follower" = "Подписчик";
"friends_add" = "Добавить в товарищи";
"friends_delete" = "Удалить из товарищей";
"friends_reject" = "Порвать приглашение в товарищи";
"friends_accept" = "Прочитать приглашение в товарищи";
"send_message" = "Отправить телеграмму";
"incoming_req" = "Подписчики";
"outcoming_req" = "Заявки";
"req" = "Заявки";
"firends_zero" = "Ни одного товарища";
"friends_one" = "$1 товарищ";
"friends_few" = "$1 товарища";
"friends_many" = "$1 товарищей";
"friends_other" = "$1 друзей";
"followers_zero" = "Ни одного подписчика";
"followers_one" = "$1 подписчик";
"followers_few" = "$1 подписчика";
"followers_many" = "$1 подписчиков";
"followers_other" = "$1 подписчиков";
"subscriptions_zero" = "Ни одной подписки";
"subscriptions_one" = "$1 подписка";
"subscriptions_few" = "$1 подписки";
"subscriptions_many" = "$1 подписок";
"subscriptions_other" = "$1 подписок";
/* Group */
"name_group" = "Название";
"subscribe" = "Подписаться";
"unsubscribe" = "Отписаться";
"subscriptions" = "Подписки";
"join_community" = "Вступить в группу";
"leave_community" = "Выйти из группы";
"min_6_community" = "Название должно быть не менее 6 символов";
"participants" = "Участники";
"groups" = "Группы";
"meetings" = "Встречи";
"create_group" = "Создать группу";
"group_managers" = "Руководство";
"group_type" = "Тип группы";
"group_type_open" = "Это открытая группа. В неё может вступить любой желающий.";
"group_type_closed" = "Это закрытая группа. Для вступления необходимо подавать заявку.";
"creator" = "Создатель";
"administrators" = "Администраторы";
"add_to_left_menu" = "Добавить в левое меню";
"remove_from_left_menu" = "Удалить из левого меню";
"all_followers" = "Все подписчики";
"only_administrators" = "Только администраторы";
"website" = "Сайт";
"managed" = "Управляемые";
"administrators_one" = "$1 администратор";
"administrators_few" = "$1 администратора";
"administrators_other" = "$1 администраторов";
"role" = "Роль";
"administrator" = "Администратор";
"promote_to_admin" = "Повысить до администратора";
"promote_to_owner" = "Назначить владельцем";
"devote" = "Разжаловать";
"set_comment" = "Изменить комментарий";
"hidden_yes" = "Скрыт: Да";
"hidden_no" = "Скрыт: Нет";
"group_allow_post_for_everyone" = "Разрешить публиковать записи всем";
"statistics" = "Статистика";
"group_administrators_list" = "Список админов";
"group_display_only_creator" = "Отображать только создателя группы";
"group_display_all_administrators" = "Отображать всех администраторов";
"group_dont_display_administrators_list" = "Ничего не отображать";
"group_changeowner_modal_title" = "Передача прав владельца";
"group_changeowner_modal_text" = "Внимание! Вы передаёте права владельца пользователю $1. Это действие необратимо. После передави вы останетесь адмиинстратором, но сможете легко перестать им быть.";
"group_owner_setted" = "Новый владелец ($1) успешно назначен в сообщество $2. Вам выданы права администратора в сообществе. Если Вы хотите вернуть роль владельца, обратитесь в <a href='/support?act=new'>техническую поддержку сайта</a>.";
"participants_zero" = "Ни одного участника";
"participants_one" = "Один участник";
"participants_few" = "$1 участника";
"participants_many" = "$1 участников";
"participants_other" = "$1 участников";
"groups_zero" = "Ни одной группы";
"groups_one" = "Одна группа";
"groups_few" = "$1 группы";
"groups_many" = "$1 групп";
"groups_other" = "$1 групп";
"meetings_zero" = "Ни одной встречи";
"meetings_one" = "Одна встреча";
"meetings_few" = "$1 встречи";
"meetings_many" = "$1 встреч";
"meetings_other" = "$1 встреч";
/* Albums */
"create" = "Создать";
"albums" = "Альбомы";
"create_album" = "Создать альбом с картинками";
"edit_album" = "Поправить альбом с картинками";
"creating_album" = "Создание альбома с картинками";
"upload_photo" = "Отправить картинку";
"photo" = "Картинка";
"upload_button" = "Картинка";
"open_original" = "Посмотреть оригинал картинки";
"avatar_album" = "Картинки из досье";
"wall_album" = "Картинки с доски";
"albums_zero" = "Ни одного альбома с картинками";
"albums_one" = "Один альбом с картинками";
"albums_few" = "$1 альбома с картинками";
"albums_many" = "$1 альбомов с картинками";
"albums_other" = "$1 альбомов с картинками";
/* Notes */
"notes" = "Черновики";
"note" = "Черновик";
"name_note" = "Название";
"text_note" = "Содержание";
"create_note" = "Написать новый черновик";
"actions" = "Действия";
"notes_zero" = "Ни одного черновика";
"notes_one" = "Один черновик";
"notes_few" = "$1 черновика";
"notes_many" = "$1 черновиков";
"notes_other" = "$1 черновиков";
/* Menus */
"edit_button" = "корр.";
"my_page" = "Мое Досье";
"my_friends" = "Мои Товарищи";
"my_photos" = "Мои Фотокартинки";
"my_videos" = "Мои Киноленты";
"my_messages" = "Мои Телеграмы";
"my_notes" = "Мои Записки";
"my_groups" = "Мои Клубы";
"my_feed" = "Мое Информбюро";
"my_feedback" = "Мои Сводки";
"my_settings" = "Мои Настройки";
"bug_tracker" = "Доска задач";
"menu_login" = "Вход";
"menu_registration" = "Регистрация";
"menu_help" = "Справка";
"menu_logout" = "Выйти";
"menu_support" = "Поддержка";
"header_home" = "главная";
"header_groups" = "клубы";
"header_people" = "граждане";
"header_invite" = "пригласить";
"header_help" = "справка";
"header_log_out" = "эмиграция";
"header_search" = "Розыск";
"header_login" = "вход";
"header_registration" = "регистрация";
"left_menu_donate" = "Поддержать";
"footer_blog" = "доска новостей";
"footer_help" = "помощь";
"footer_developers" = "госслужащим";
"footer_choose_language" = "выбрать язык";
"footer_privacy" = "секретность";
/* Settings */
"main" = "Основное";
"contacts" = "Контакты";
"avatar" = "Картинка";
"privacy" = "Секретность";
"interface" = "Внешний вид";
"profile_picture" = "Изображение страницы";
"picture" = "Изображение";
"change_password" = "Изменить кодовое слово";
"old_password" = "Старое кодовое слово";
"new_password" = "Новое кодовое слово";
"repeat_password" = "Повторите кодовое слово";
"avatars_style" = "Отображение картинок";
"style" = "Стиль";
"default" = "По умолчанию";
"cut" = "Обрезка";
"round_avatars" = "Круглая картинка";
"search_for_groups" = "Розыск клубов";
"search_for_people" = "Розыск граждан";
"search_button" = "Найти";
"search_placeholder" = "Начните вводить любое имя, название или слово";
"results_zero" = "Ни одного результата";
"results_one" = "Один результат";
"results_few" = "$1 результата";
"results_many" = "$1 результатов";
"results_other" = "$1 результатов";
"privacy_setting_access_page" = "Кому из граждан видно мое досье";
"privacy_setting_read_info" = "Кому видно основную информацию моей страницы";
"privacy_setting_see_groups" = "Кому разрешено просматривать мои картинки и встречи";
"privacy_setting_see_photos" = "Кому разрешено просматривать мои картинки";
"privacy_setting_see_videos" = "Кому разрешено смотреть мои киноленты";
"privacy_setting_see_notes" = "Кому разрешено просматривать мои черновики";
"privacy_setting_see_friends" = "Кому видно моих товарщией";
"privacy_setting_add_to_friends" = "Кто может звать меня товарищем";
"privacy_setting_write_wall" = "Кто может оставлять записи на доске";
"privacy_setting_write_messages" = "Кто может отправлять мне телеграммы";
"privacy_value_anybody" = "Все граждане";
"privacy_value_anybody_dative" = "Всем гражданинам";
"privacy_value_users" = "Участникам органа OpenVK";
"privacy_value_friends" = "Товарищи";
"privacy_value_friends_dative" = "Товарищам";
"privacy_value_only_me" = "Только я и КГБ";
"privacy_value_only_me_dative" = "Только мне и КГБ";
"privacy_value_nobody" = "Никто";
"your_email_address" = "Адрес Вашего почтового ящика";
"your_page_address" = "Адрес Вашего досье";
"page_address" = "Адрес досье";
"current_email_address" = "Текущий адрес";
"page_id" = "Номер досье";
"you_can_also" = "Вы также можете";
"delete_your_page" = "порвать свое досье";
"delete_album" = "выкинуть свой альбом с картинками";
"ui_settings_interface" = "Интерфейс";
"ui_settings_sidebar" = "Левое меню";
"ui_settings_rating" = "Рейтинг";
"ui_settings_rating_show" = "Показывать";
"ui_settings_rating_hide" = "Скрывать";
"additional_links" = "Дополнительные ссылки";
/* Two-factor authentication */
"two_factor_authentication" = "Двухфакторная аутентификация";
"two_factor_authentication_disabled" = "Обеспечивает надежную защиту от взлома: для входа на страницу необходимо ввести код, полученный в приложении 2FA.";
"two_factor_authentication_enabled" = "Двухфакторная аутентификация включена. Ваша страница защищена.";
"two_factor_authentication_login" = "У вас включена двухфакторная аутентификация. Для входа введите код полученный в приложении.";
"two_factor_authentication_settings_1" = "Двухфакторную аутентификацию через TOTP можно использовать даже без интернета. Для этого вам понадобится приложение для генерации кодов. Например, <b>Google Authenticator</b> для Android и iOS или свободные <b>Aegis и andOTP</b> для Android. Убедитесь, что на телефоне точно установлена дата и время.";
"two_factor_authentication_settings_2" = "Используя приложение для двухфакторной аутентификации, отсканируйте приведенный ниже QR-код:";
"two_factor_authentication_settings_3" = "или вручную введите секретный ключ: <b>$1</b>.";
"two_factor_authentication_settings_4" = "Теперь введите код, который вам предоставило приложение, и пароль от вашей страницы, чтобы мы могли подтвердить, что вы действительно вы.";
"connect" = "Подключить";
"enable" = "Включить";
"disable" = "Отключить";
"code" = "Код";
"2fa_code" = "Код 2FA";
"incorrect_password" = "Неверный пароль";
"incorrect_code" = "Неверный код";
"incorrect_2fa_code" = "Неверный код двухфакторной аутентификации";
"two_factor_authentication_enabled_message" = "Двухфакторная аутентификация включена";
"two_factor_authentication_enabled_message_description" = "Вашу страницу стало труднее взломать. Рекомендуем вам скачать <a href='javascript:viewBackupCodes()'>резервные коды</a>";
"two_factor_authentication_disabled_message" = "Двухфакторная аутентификация отключена";
"view_backup_codes" = "Посмотреть резервные коды";
"backup_codes" = "Резервные коды для подтверждения входа";
"two_factor_authentication_backup_codes_1" = "Резервные коды позволяют подтверждать вход, когда у вас нет доступа к телефону, например, в путешествии.";
"two_factor_authentication_backup_codes_2" = "У вас есть ещё <b>10 кодов</b>, каждым кодом можно воспользоваться только один раз. Распечатайте их, уберите в надежное место и используйте, когда потребуются коды для подтверждения входа.";
"two_factor_authentication_backup_codes_3" = "Вы можете получить новые коды, если они заканчиваются. Действительны только последние созданные резервные коды.";
/* Sorting */
"sort_randomly" = "Сортировать случайно";
"sort_up" = "Сортировать по дате создания вверх";
"sort_down" = "Сортировать по дате создания вниз";
/* Videos */
"videos" = "Киноленты";
"video" = "Кинолента";
"upload_video" = "Отправить киноленту";
"video_uploaded" = "Отправлено";
"video_updated" = "Изменено";
"video_link_to_yt" = "Номер на YouTube";
"info_name" = "Название";
"info_description" = "Описание";
"info_uploaded_by" = "Отправил";
"info_upload_date" = "Дата отправки киноленты";
"videos_zero" = "Ни однойкиноленты";
"videos_one" = "Одна кинолента";
"videos_few" = "$1 киноленты";
"videos_many" = "$1 кинолент";
"videos_other" = "$1 кинолент";
/* Notifications */
"feedback" = "Ответы";
"unread" = "Непрочитанное";
"archive" = "Архив";
"notifications_like" = "$1 оценил вашу $2запись$3 от $4";
"notifications_repost" = "$1 поделился(-лась) вашей $2записью$3 от $4";
"notifications_comment_under" = "$1 оставил(-ла) комментарий под $2";
"notifications_under_note" = "вашей $3заметкой$4";
"notifications_under_photo" = "вашим $3фото$4";
"notifications_under_post" = "вашей $3записью$4 от $5";
"notifications_under_video" = "вашей $3кинолентой$4";
"notifications_post" = "$1 написал(-ла) $2запись$3 на вашей стене: $4";
"notifications_appoint" = "$1 назвачил вас руководителем сообщества $2";
"nt_liked_yours" = "понравился ваш";
"nt_shared_yours" = "поделился(-ась) вашим";
"nt_commented_yours" = "оставил(а) комментарий под";
"nt_written_on_your_wall" = "написал(а) на вашей стене";
"nt_made_you_admin" = "назначил(а) вас руководителем сообщества";
"nt_from" = "от";
"nt_yours_adjective" = "вашим";
"nt_yours_feminitive_adjective" = "вашей";
"nt_post_nominative" = "запись";
"nt_post_instrumental" = "записью";
"nt_note_instrumental" = "черновиком";
"nt_photo_instrumental" = "картинкой";
"nt_topic_instrumental" = "темой";
/* Time */
"time_at_sp" = " в ";
"time_just_now" = "только что";
"time_exactly_five_minutes_ago" = "ровно 5 минут назад";
"time_minutes_ago" = "$1 минут назад";
"time_today" = "сегодня";
"time_yesterday" = "вчера";
"points" = "Советские рубли";
"points_count" = "советских рублей";
"on_your_account" = "на вашем счету";
"vouchers" = "Лотерейные карточки";
"have_voucher" = "Есть лотерейная карточка";
"voucher_token" = "Код лотерейной карточки";
"voucher_activators" = "Воспользовавшиеся";
"voucher_explanation" = "Товарищ, введите сюда кодовый номер лотерейной карточки. Орган указывает его в вашем чеке или телеграмме.";
"voucher_explanation_ex" = "Мы забираем лотерейные карточки, дубликаты отклоняются.";
"invalid_voucher" = "Такуя лоетрейную карточку мы уже приняли";
"voucher_bad" = "Товращи, мы уже принимали такую карточку, либо её срок истёк.";
"voucher_good" = "Лотерейная карточка активирован";
"voucher_redeemed" = "Товарищ, благодарим за отправку карточки! Мы жуе начислили по ней рубли, но вы больше не сможете их повторно получить по той карточке.";
"redeem" = "Активировать лотерейную карточку";
"deactivate" = "Порвать";
"usages_total" = "Количество использований";
"usages_left" = "Осталось использований";
"points_transfer_dialog_header_1" = "Вы можете отправить в подарок или передать часть рублей другому гражданину.";
"points_transfer_dialog_header_2" = "Ваш текущий баланс:";
"points_amount_one" = "1 рубль";
"points_amount_few" = "$1 рубля";
"points_amount_many" = "$1 рублей";
"points_amount_other" = "$1 рублей";
"transfer_poins" = "Передача рублей";
"transfer_poins_button" = "Передать рубли";
"also_you_can_transfer_points" = "Также вы можете <a href=\"javascript:showCoinsTransferDialog($1, '$2')\">передать рубли</a> другому гражданину.";
"transferred_to_you" = "передал вам";
"receiver_address" = "Адрес досье получателя";
"coins_count" = "Количество рублей";
"message" = "Сообщение";
"failed_to_tranfer_points" = "Не удалось передать рубли";
"points_transfer_successful" = "Вы успешно передали <b>$1 <a href=\"$2\">$3</a></b>.";
"not_all_information_has_been_entered" = "Введена не вся информация.";
"negative_transfer_value" = "Орган не подразумевает нарушения закона, чтобы украсть чужие деньги.";
"message_is_too_long" = "Сообщение слишком длинное.";
"receiver_not_found" = "Гражданин не найден.";
"you_dont_have_enough_points" = "У вас недостаточно рублей.";
/* Gifts */
"gift" = "Подарок";
"gifts" = "Подарки";
"gifts_zero" = "Нет подарков";
"gifts_one" = "Один подарок";
"gifts_few" = "$1 подарка";
"gifts_many" = "$1 подарков";
"gifts_other" = "$1 подарков";
"gifts_left" = "Подарков осталось: $1";
"gifts_left_one" = "Один подарок остался";
"gifts_left_few" = "$1 подарка осталось";
"gifts_left_many" = "$1 подарков осталось";
"gifts_left_other" = "$1 подарков осталось";
"send_gift" = "Отправить подарок";
"gift_select" = "Выбрать подарок";
"collections" = "Коллекции";
"confirm" = "Подтверждение";
"as_anonymous" = "Анонимно";
"gift_your_message" = "Ваше сообщение";
"free_gift" = "Бесплатно";
"coins" = "Голоса";
"coins_zero" = "0 рублей";
"coins_one" = "Один рубль";
"coins_few" = "$1 рубля";
"coins_many" = "$1 рублей";
"coins_other" = "$1 рублей";
"users_gifts" = "Подарки";
/* Support */
"support_opened" = "Открытые";
"support_answered" = "С ответом";
"support_closed" = "Закрытые";
"support_ticket" = "Обращение";
"support_tickets" = "Обращения";
"support_status_0" = "Вопрос на рассмотрении";
"support_status_1" = "Есть ответ";
"support_status_2" = "Закрыто";
"support_greeting_hi" = "Здравствуйте, $1!";
"support_greeting_regards" = "С уважением,<br/>команда поддержки $1.";
"support_faq" = "Часто задаваемые вопросы";
"support_list" = "Список обращений";
"support_new" = "Новое обращение";
"support_faq_title" = "Для кого этот сайт?";
"support_faq_content" = "Сайт предназначен для поиска друзей и знакомых, а также для просмотра данных пользователя. Это как справочник города, с помощью которого люди могут быстро найти актуальную информацию о человеке.";
"support_new_title" = "Введите тему вашего обращения";
"support_new_content" = "Опишите проблему или предложение";
"support_rate_good_answer" = "Это хороший ответ";
"support_rate_bad_answer" = "Это плохой ответ";
"support_good_answer_user" = "Вы оставили положительный отзыв.";
"support_bad_answer_user" = "Вы оставили негативный отзыв.";
"support_good_answer_agent" = "Гражданин оставил положительный отзыв";
"support_bad_answer_agent" = "Гражданин оставил негативный отзыв";
"support_rated_good" = "Вы оставили положительный отзыв об ответе.";
"support_rated_bad" = "Вы оставили негативный отзыв об ответе.";
"wrong_parameters" = "Неверные параметры запроса.";
"fast_answers" = "Быстрые ответы";
"comment" = "Отзыв";
"sender" = "Отправитель";
"author" = "Автор";
"you_have_not_entered_text" = "Вы не ввели текст";
"you_have_not_entered_name_or_text" = "Вы не ввели имя или текст";
"ticket_changed" = "Тикет изменён";
"ticket_changed_comment" = "Изменения вступят силу через несколько секунд.";
/* Invite */
"invite" = "Позвать";
"you_can_invite" = "Товарищ, вы можете позвать своих товарщией в орган с помощью индивидуального номера ссылки:";
"you_can_invite_2" = "Приложите номер ссылки к вашей телеграмме. Гражданин вступит в орган и вы сразу станете товарищами.";
/* Banned */
"banned_title" = "Вам бан";
"banned_header" = "Вы были отправлены в тюрьму";
"banned_alt" = "Гражданин был отправлен в тюрьму.";
"banned_1" = "Извините, <b>$1</b>, но вы были отправлены в тюрьму.";
"banned_2" = "А причина этому проста: <b>$1</b>. Органу в этот раз пришлось отправить вас под стражу навсегда.";
"banned_3" = "Вы всё ещё можете <a href=\"/support?act=new\">написать в службу поддержки</a>, если считаете что произошла ошибка или <a href=\"/logout?hash=$1\">выйти</a>.";
/* Discussions */
"discussions" = "Обсуждения";
"messages_one" = "Одна телеграмма";
"messages_few" = "$1 телеграмм";
"messages_many" = "$1 телеграмм";
"messages_other" = "$1 телеграмм";
"topic_messages_count_zero" = "В теме нет телеграмм";
"topic_messages_count_one" = "В теме одна телеграмма";
"topic_messages_count_few" = "В теме $1 телеграмм";
"topic_messages_count_many" = "В теме $1 телеграмм";
"topic_messages_count_other" = "В теме $1 телеграмм";
"replied" = "ответил";
"create_topic" = "Создать тему";
"new_topic" = "Новая тема";
"title" = "Заголовок";
"text" = "Текст";
"view_topic" = "Просмотр темы";
"edit_topic_action" = "Редактировать тему";
"edit_topic" = "Редактирование темы";
"topic_settings" = "Настройки темы";
"pin_topic" = "Закрепить тему";
"close_topic" = "Закрыть тему";
"delete_topic" = "Удалить тему";
"topics_one" = "Одна тема";
"topics_few" = "$1 темы";
"topics_many" = "$1 тема";
"topics_other" = "$1 тем";
"created" = "Создано";
"everyone_can_create_topics" = "Все могут создавать темы";
"display_list_of_topics_above_wall" = "Отображать список тем над стеной";
"topic_changes_saved_comment" = "Обновлённый заголовок и настройки появятся на странице с темой.";
"failed_to_create_topic" = "Не удалось создать тему";
"failed_to_change_topic" = "Не удалось изменить тему";
"no_title_specified" = "Заголовок не указан.";
/* Errors */
"error_1" = "Некорректный запрос";
"error_2" = "Неверный логин или пароль";
"error_3" = "Не авторизован";
"error_4" = "Пользователь не существует";
"information_-1" = "Операция выполнена успешно";
"information_-2" = "Вход выполнен успешно";
"no_data" = "Нет данных";
"no_data_description" = "Товарищ, на этой доске нету записей.";
"error" = "Ошибка";
"error_shorturl" = "Данный короткий адрес уже занят.";
"error_segmentation" = "Ошибка сегментации";
"error_upload_failed" = "Не удалось загрузить фото";
"error_old_password" = "Старый пароль не совпадает";
"error_new_password" = "Новые пароли не совпадает";
"error_shorturl_incorrect" = "Короткий адрес имеет некорректный формат.";
"error_repost_fail" = "Не удалось поделиться записью";
"forbidden" = "Ошибка доступа";
"forbidden_comment" = "Настройки приватности этого пользователя не разрешают вам смотреть на его страницу.";
"changes_saved" = "Изменения сохранены";
"changes_saved_comment" = "Товарищ, обоновлённые данные появятся на вашем досье.";
"photo_saved" = "Картинка сохранена";
"photo_saved_comment" = "Товарищ, орган одобрил новую картинку в вашем досье.";
"shared_succ" = "Запись появится на вашей доске. Нажмите на уведомление, чтобы перейти к своей стене.";
"invalid_email_address" = "Неверный адрес почтового ящика";
"invalid_email_address_comment" = "Товарищ, нам не удалось найти ваш почтовый ящик.";
"invalid_telegram_name" = "Неверное имя Telegram аккаунта";
"invalid_telegram_name_comment" = "Вы ввели неверное имя аккаунта Telegram.";
"invalid_birth_date" = "Неверная дата рождения";
"invalid_birth_date_comment" = "Дата рождения, которую вы ввели, не является корректной.";
"token_manipulation_error" = "Ошибка манипулирования токеном";
"token_manipulation_error_comment" = "Токен недействителен или истёк";
"profile_changed" = "Досье изменёно";
"profile_changed_comment" = "Товарищ, орган одобрил изменение вашего досье.";
"profile_not_found" = "Гражданин не найден.";
"suspicious_registration_attempt" = "Подозрительная попытка регистрации в орган";
"suspicious_registration_attempt_comment" = "Товарищ, а вы откуда к нам пришли? Вы очень подозрительно себя ведёте.";
"rate_limit_error" = "Чумба, ты совсем ёбнутый?";
"rate_limit_error_comment" = "Сходи к мозгоправу, попей колёсики. В $1 нельзя вбрасывать щитпосты так часто. Код исключения: $2.";
"not_enough_permissions" = "Недостаточно прав";
"not_enough_permissions_comment" = "У вас недостаточно прав чтобы выполнять это действие.";
"login_required_error" = "Недостаточно прав";
"login_required_error_comment" = "Чтобы просматривать эту страницу, нужно зайти на сайт.";
"captcha_error" = "Неправильно введены символы";
"captcha_error_comment" = "Пожалуйста, убедитесь, что вы правильно заполнили поле с капчей.";
/* Admin actions */
"login_as" = "Войти как $1";
"manage_user_action" = "Управление гражданином";
"manage_group_action" = "Управление клубом";
"ban_user_action" = "Заблокировать гражданина";
"warn_user_action" = "Предупредить гражданина";
/* Paginator (deprecated) */
"paginator_back" = "Назад";
"paginator_page" = "Страница $1";
"paginator_next" = "Дальше";
/* About */
"about_openvk" = "Об органе OpenVK";
/* Dialogs */
"ok" = "ОК";
"yes" = "Да";
"no" = "Нет";
"cancel" = "Отмена";
"edit_action" = "Изменить";
"transfer" = "Передать";
"close" = "Закрыть";
"warning" = "Внимание";
"question_confirm" = "Товарищ, будьте внимательны с выбором. Вы согласны с вашим выбором? Отменить не представляется возможным.";
/* User alerts */
"user_alert_scam" = "Органу управления было дозволено, что данный гражданин обманывает товарищей на денежные средства. Будьте осторожны при разговоре с ним.";

811
locales/udm.strings Normal file
View file

@ -0,0 +1,811 @@
"__locale" = "ru_UDM.utf8;ru_UDM.UTF-8;Udm";
"__WinEncoding" = "Windows-1251";
/* Main page */
"home" = "Валтӥсь";
"welcome" = "Гажаса ӧтиськом";
/* Login */
"log_in" = "Пырон";
"password" = "Пароль";
"registration" = "Регистрация";
"forgot_password" = "Вунэтоно пароль?";
"login_failed" = "Пырыса ӧз удалты";
"invalid_username_or_password" = "Пользователь пароль ним яке мыдлань. <a href='/restore.pl'>Забыли пароль?</a>";
"failed_to_register" = "Не удалось зарегистрироваться";
"referral_link_invalid" = "Недействительный ссылка ӧтён.";
"registration_disabled" = "Регистрация радлы отключена администратором.";
"user_already_exists" = "Пользователь email сыӵе ини ӵош улӥськом.";
"access_recovery" = "Восстановление доступа";
"page_access_recovery" = "Восстановя доступ к странице";
"access_recovery_info" = "Забыли пароль? Бугыръяське, тонэн ӵош тон мыным но келялозы валэктон восстановление email to юри сямен пырозы.";
"access_recovery_info_2" = "Введите выль пароль. Все текущие сеансы будут приостановлены и токены доступа будут аннулированы.";
"reset_password" = "Сбросить пароль";
"2fa_code_2" = "Код двухфакторной аутентификации";
"password_successfully_reset" = "Ваш пароль был успешно сброшен.";
"password_reset_email_sent" = "Если вы зарегистрированы, вы получите инструкции на email.";
"password_reset_error" = "Непредвиденная ошибка при сбросе пароля.";
"password_reset_rate_limit_error" = "Нельзя делать это так часто, извините.";
"registration_disabled_info" = "Регистрация отключена системным администратором. При возможности попросите приглашение у вашего знакомого, если он зарегистрирован на этом сайте.";
"registration_closed" = "Регистрация закрыта.";
"invites_you_to" = "<strong>$1</strong> приглашает вас в $2";
"register_meta_desc" = "Зарегистрируйтесь в $1 прямо сейчас!";
"register_referer_meta_title" = "$1 приглашает вас в $2!";
"register_referer_meta_desc" = "Присоединяйтесь к $1 и множеству других пользователей в $2!";
"users" = "Пользователи";
/* Profile information */
"select_language" = "Быръе кыл";
"edit" = "Воштыны";
"birth_date" = "Вордӥськем нунал";
"registration_date" = "Дата регистрации";
"hometown" = "Вордскем город";
"this_is_you" = "та Тон";
"edit_page" = "Редактировать страницу";
"edit_group" = "Редактировать группу";
"change_status" = "воштыны инлыкез";
"name" = "Нимыз";
"surname" = "Фамилиосты";
"gender" = "Выж";
"male" = "пиосмурт";
"female" = "нылкышно";
"description" = "Описание";
"save" = "Утьыны";
"main_information" = "Основная ивортодэт";
"nickname" = "Никнейм";
"online" = "Вотэсын";
"was_online" = "был вотэсын";
"was_online_m" = "был вотэсын";
"was_online_f" = "была вотэсын";
"all_title" = "Все";
"information" = "Ивортодэт";
"status" = "Статус";
"no_information_provided" = "Ивортодэт отсутствует.";
"deceased_person" = "Бам кышка адями";
"none" = "отсутствует";
"send" = "Ыстыны";
"years_zero" = "0 ар";
"years_one" = "1 ар";
"years_few" = "$1 ар";
"years_many" = "$1 ар";
"years_other" = "$1 ар";
"relationship" = "Семейное положение";
"relationship_0" = "Ӧз быръе";
"relationship_1" = "Кышнояськыны уг";
"relationship_2" = "Пумиськизы";
"relationship_3" = "Помолвлен";
"relationship_4" = "Кышнояськи";
"relationship_5" = "Гражданской брак-ын";
"relationship_6" = "Ог-огзэс яратыса";
"relationship_7" = "Сложной вань";
"relationship_8" = "В активном поиске";
"politViews" = "Политической учке";
"politViews_0" = "Ӧз быръе";
"politViews_1" = "Индифферентные";
"politViews_2" = "Коммунистические";
"politViews_3" = "Социалистические";
"politViews_4" = "Зӥбломыт";
"politViews_5" = "Либеральные";
"politViews_6" = "Консервативные";
"politViews_7" = "Монархические";
"politViews_8" = "Ультраконсервативные";
"politViews_9" = "Либертарианские";
"contact_information" = "Тодэтъёс";
"email" = "Электронная почта";
"phone" = "Телефон";
"telegram" = "Telegram";
"personal_website" = "Личной сайт";
"city" = "Город";
"address" = "Адресъёсын";
"personal_information" = "Личной информация";
"interests" = "Тунсыкъёссэс";
"favorite_music" = "Яратоно крезьгурез";
"favorite_films" = "Яратоно фильмы";
"favorite_shows" = "Яратоно ТВ-шоу";
"favorite_books" = "Яратоно книги";
"favorite_quotes" = "Яратоно цитаты";
"information_about" = "Ачим сярысь";
"updated_at" = "Обновлено $1";
"user_banned" = "Жаляса верано луэ, мон луэ заблокировать пользователя <b>$1</b>.";
"user_banned_comment" = "Комментарий модератора:";
/* Wall */
"feed" = "Иворъёс";
"post_writes_m" = "гожтыны";
"post_writes_f" = "гожтыны";
"post_writes_g" = "опубликовало";
"wall" = "Борддор";
"post" = "Запись";
"write" = "Гожтыны";
"publish" = "Опубликовать";
"delete" = "Палэнтыны";
"comments" = "Комментарии";
"share" = "Поделиться";
"pin" = "Вери";
"unpin" = "Открепить";
"pinned" = "вери";
"comments_tip" = "Лу нырысетӥ, кин кельтыны комментарий!";
"your_comment" = "Тон комментарий";
"shown" = "Возьмалэ";
"x_out_of" = "$1 из";
"wall_zero" = "записей ӧвӧл";
"wall_one" = "одӥг запись";
"wall_few" = "$1 записи";
"wall_many" = "$1 записей";
"wall_other" = "$1 записей";
"publish_post" = "Ватсан записи";
"view_other_comments" = "Учке мукет комментарий";
"no_comments" = "Комментариев ӧвӧл";
"all_news" = "Вань иворъёс";
"posts_per_page" = "Количество записей на странице";
"attachment" = "Вложение";
"post_as_group" = "Нимысьтыз сообщество";
"comment_as_group" = "Нимысьтыз сообщество";
"add_signature" = "Авторен гожтэм";
"contains_nsfw" = "Вордскем NSFW-контент";
"nsfw_warning" = "Сётэм визь сюдыны-вордыны быгато 18+ контент";
"report" = "Урттылӥськиз";
"attach" = "Юнматӥзы";
"attach_photo" = "Туспуктэмез юнматэмын";
"attach_video" = "Видео юнматӥзы";
"draw_graffiti" = "Граффити суредамын";
"no_posts_abstract" = "Татын нокин номыр уг гожтӥськы.";
"attach_no_longer_available" = "Та вложение трос валантэмез.";
"open_post" = "Усьты запись";
"version_incompatibility" = "Та вложение возьматытэк ӧйлась. Оло, юри несовместимый версия OpenVK базаын бызиз.";
"reply" = "Ответить";
/* Friends */
"friends" = "Эшъёс";
"followers" = "Подписчики";
"follower" = "Подписчик";
"friends_add" = "Ог ватсаны";
"friends_delete" = "Эшъёсы пӧлысь палэнтыны";
"friends_reject" = "Отменить заявку";
"friends_accept" = "Принять заявку";
"send_message" = "Отправить сообщение";
"incoming_req" = "Подписчики";
"outcoming_req" = "Заявки";
"req" = "Заявки";
"firends_zero" = "Одӥг но эшъёс";
"friends_one" = "$1 эшъёс";
"friends_few" = "$1 эшъёс";
"friends_many" = "$1 эшъёс";
"friends_other" = "$1 эшъёс";
"followers_zero" = "Одӥг но подписчика";
"followers_one" = "$1 подписчик";
"followers_few" = "$1 подписчика";
"followers_many" = "$1 подписчиков";
"followers_other" = "$1 подписчиков";
"subscriptions_zero" = "Одӥг но подписки";
"subscriptions_one" = "$1 подписка";
"subscriptions_few" = "$1 подписки";
"subscriptions_many" = "$1 подписок";
"subscriptions_other" = "$1 подписок";
/* Group */
"name_group" = "Нимыз";
"subscribe" = "Подписаться";
"unsubscribe" = "Отписаться";
"subscriptions" = "Подписки";
"join_community" = "Группаязы пыре";
"leave_community" = "Группаысь потытэк";
"min_6_community" = "6 символэз возиськыны уг луы куло ӧжыт";
"participants" = "Пыриськисьёс";
"groups" = "Группы";
"meetings" = "Пумиськон";
"create_group" = "Кылдӥз группу";
"group_managers" = "Кивалтонни";
"group_type" = "Тип группы";
"group_type_open" = "Та группа усьтыны. Отчы пырыны быгатэ котькудӥз мылкыд карись.";
"group_type_closed" = "Та ӵогам группа. Заявка сётыны кулэ пырон понна.";
"creator" = "Кылдӥз";
"administrators" = "Администраторы";
"add_to_left_menu" = "Паллян менюысь ватсаны";
"remove_from_left_menu" = "Паллян менюысь палэнтыны";
"all_followers" = "Все подписчики";
"only_administrators" = "Только администраторы";
"website" = "Сайт";
"managed" = "Управляемые";
"administrators_one" = "$1 администратор";
"administrators_few" = "$1 администратора";
"administrators_other" = "$1 администраторов";
"role" = "Рольёсты";
"administrator" = "Администратор";
"promote_to_admin" = "Озь будэтӥз администратора";
"promote_to_owner" = "Дасямын владельцем";
"devote" = "Разжаловать";
"set_comment" = "Воштыны комментарий";
"hidden_yes" = "Ватэм: Мед";
"hidden_no" = "Ватэм: Ӧвӧл";
"group_allow_post_for_everyone" = "Вань гожъямъёссэ поттыса лэзе";
"statistics" = "Статистика";
"group_administrators_list" = "Список админов";
"group_display_only_creator" = "Возьмаса гинэ создателя группы";
"group_display_all_administrators" = "Администратор вань возьмалэ";
"group_dont_display_administrators_list" = "Номыр но уг возьматы";
"group_changeowner_modal_title" = "Передача право кузё";
"group_changeowner_modal_text" = "Сак! Тыныд право сётӥз кузёйыръёс пользователь $1. Та ужрад необратимый. Передача бере, тӥледлы кыле на администраторлэсь но, со капчиен быгатэ луыны дугдӥз.";
"group_owner_setted" = "Выль кузё ($1) пусъемын йыг сообщество $2. Администратор сообществоын тыныд право сётӥз. Рольёсъя Тон кузёйыр берыктэмед потэ ке, пӧрмиз <a href='/support?act=new'>техническую поддержку сайта</a>.";
"participants_zero" = "Но одӥг пыриськисьёс";
"participants_one" = "Одӥг пыриськисьёс";
"participants_few" = "$1 пыриськисьёс";
"participants_many" = "$1 пыриськисьёс";
"participants_other" = "$1 пыриськисьёс";
"groups_zero" = "Но одӥг группа";
"groups_one" = "Одӥг группаын";
"groups_few" = "$1 группаын";
"groups_many" = "$1 группаын";
"groups_other" = "$1 группаын";
"meetings_zero" = "Но одӥг пумиськон";
"meetings_one" = "Одӥг пумиськон";
"meetings_few" = "$1 пумиськон";
"meetings_many" = "$1 пумиськон";
"meetings_other" = "$1 пумиськон";
/* Albums */
"create" = "Кылдӥз";
"albums" = "Альбомы";
"create_album" = "Кылдӥз альбом";
"edit_album" = "Редактировать альбом";
"creating_album" = "Создание альбома";
"upload_photo" = "Туспуктэм etkileşimli";
"photo" = "Туспуктэм";
"upload_button" = "Etkileşimli";
"open_original" = "Открыть оригинал";
"avatar_album" = "Ӵош туспуктэм бам";
"wall_album" = "Борддорысь туспуктэмъёсты";
"albums_zero" = "Одӥг но альбом";
"albums_one" = "Одӥг альбом";
"albums_few" = "$1 альбома";
"albums_many" = "$1 альбомов";
"albums_other" = "$1 альбомов";
/* Notes */
"notes" = "Заметки";
"note" = "Заметка";
"name_note" = "Нимыз";
"text_note" = "Содержание";
"create_note" = "Кылдӥз заметку";
"actions" = "Ужъёс";
"notes_zero" = "Ни одной заметки";
"notes_one" = "Одна заметка";
"notes_few" = "$1 заметки";
"notes_many" = "$1 заметок";
"notes_other" = "$1 заметок";
/* Menus */
"edit_button" = "ред.";
"my_page" = "Мынам Бам";
"my_friends" = "Мынам Эшъёсы";
"my_photos" = "Мынам Туспуктэм";
"my_videos" = "Мынам Видеозаписи";
"my_messages" = "Мынам Сообщения";
"my_notes" = "Мынам Заметки";
"my_groups" = "Мынам Группы";
"my_feed" = "Мынам Новости";
"my_feedback" = "Мынам Ответы";
"my_settings" = "Мынам Настройки";
"bug_tracker" = "Баг-трекер";
"menu_login" = "Пырон";
"menu_registration" = "Регистрация";
"menu_help" = "Юрттэт";
"menu_logout" = "Потӥз";
"menu_support" = "Юрттэт";
"header_home" = "кутскон";
"header_groups" = "группы";
"header_people" = "адями";
"header_invite" = "ӧтем";
"header_help" = "юрттэт";
"header_log_out" = "потӥз";
"header_search" = "Утчан";
"header_login" = "пырон";
"header_registration" = "регистрация";
"left_menu_donate" = "юрттоз";
"footer_blog" = "блог";
"footer_help" = "юрттэт";
"footer_developers" = "разработчикам";
"footer_choose_language" = "быръе кыл";
"footer_privacy" = "приватность";
/* Settings */
"main" = "Основное";
"contacts" = "Контакты";
"avatar" = "Аватар";
"privacy" = "Приватность";
"interface" = "Педпал туссы";
"profile_picture" = "Суредъя бам";
"picture" = "Суред";
"change_password" = "Изменить пароль";
"old_password" = "Старый пароль";
"new_password" = "Новый пароль";
"repeat_password" = "Повторите пароль";
"avatars_style" = "Отображение аватар";
"style" = "Стиль";
"default" = "По умолчанию";
"cut" = "Обрезка";
"round_avatars" = "Круглый аватар";
"search_for_groups" = "Группа утчан";
"search_for_people" = "Адями утчан";
"search_button" = "Шедьтӥзы";
"search_placeholder" = "Котькудӥныз нимысьтыз пырыны кутске, нимыз яке кыл";
"results_zero" = "Одӥг но результатъёсыз";
"results_one" = "Один результат";
"results_few" = "$1 результата";
"results_many" = "$1 результатов";
"results_other" = "$1 результатов";
"privacy_setting_access_page" = "Кин милемыз адӟыса интернетын бам";
"privacy_setting_read_info" = "кин милемыз адӟоз информациез валтӥсь бам";
"privacy_setting_set_groups" = "группаен но мон адӟиськи, Кин пумитан";
"privacy_setting_see_photos" = "кин милемыз адӟоз туспуктэм";
"privacy_setting_see_videos" = "кин милемыз адӟоз видеозапись";
"privacy_setting_see_notes" = "кин милемыз адӟоз заметка";
"privacy_setting_see_friends" = "кин милемыз адӟыса, эшъёсы";
"privacy_setting_add_to_friends" = "кин луо мон мукетыз нимаське";
"privacy_setting_write_wall" = "Кин гожъяны быгатэ, мон вылэ борддор";
"privacy_setting_write_messages" = "Кин мон луись ивортонъёсты гожъяны";
"privacy_value_anybody" = "вань мылкыд карисьёс";
"privacy_value_anybody_dative" = "вань мылкыд карисьёс";
"privacy_value_users" = "Пользователь OpenVK";
"privacy_value_friends" = "Эшъёс";
"privacy_value_friends_dative" = "Эшъёс";
"privacy_value_only_me" = "мон Гинэ";
"privacy_value_only_me_dative" = "мон Гинэ";
"privacy_value_nobody" = "Нокин";
"your_email_address" = "тон электронной почта адрес";
"your_page_address" = "Тон Адресъёсын бам";
"page_address" = "Адресъёсын бам";
"current_email_address" = "Бызьыны адресъёсын";
"page_id" = "бам ID";
"you_can_also" = "тӥ озьы быгатӥськоды";
"delete_your_page" = "баме асьсэлэсь палэнтыны";
"delete_album" = "альбом палэнтыны";
"ui_settings_interface" = "Интерфейсэз";
"ui_settings_sidebar" = "паллян менюысь";
"ui_settings_rating" = "Рейтинг";
"ui_settings_rating_show" = "Возьматэ";
"ui_settings_rating_hide" = "Ватэм";
"additional_links" = "Ватсаса чӧлсконъёсыз";
/* Two-factor authentication */
"two_factor_authentication" = "Двухфакторная аутентификация";
"two_factor_authentication_disabled" = "Обеспечивает надежную защиту от взлома: для входа на страницу необходимо ввести код, полученный в приложении 2FA.";
"two_factor_authentication_enabled" = "Двухфакторная аутентификация включена. Ваша страница защищена.";
"two_factor_authentication_login" = "У вас включена двухфакторная аутентификация. Для входа введите код полученный в приложении.";
"two_factor_authentication_settings_1" = "Двухфакторную аутентификацию через TOTP можно использовать даже без интернета. Для этого вам понадобится приложение для генерации кодов. Например, <b>Google Authenticator</b> для Android и iOS или свободные <b>Aegis и andOTP</b> для Android. Убедитесь, что на телефоне точно установлена дата и время.";
"two_factor_authentication_settings_2" = "Используя приложение для двухфакторной аутентификации, отсканируйте приведенный ниже QR-код:";
"two_factor_authentication_settings_3" = "или вручную введите секретный ключ: <b>$1</b>.";
"two_factor_authentication_settings_4" = "Теперь введите код, который вам предоставило приложение, и пароль от вашей страницы, чтобы мы могли подтвердить, что вы действительно вы.";
"connect" = "Подключать";
"enable" = "Ӝуаз";
"disable" = "Отключить";
"code" = "Кода";
"2fa_code" = "Кода 2FA";
"incorrect_password" = "Неверный пароль";
"incorrect_code" = "Неверный код";
"incorrect_2fa_code" = "Неверный код двухфакторной аутентификации";
"two_factor_authentication_enabled_message" = "Двухфакторная аутентификация включена";
"two_factor_authentication_enabled_message_description" = "Вашу страницу стало труднее взломать. Рекомендуем вам скачать <a href='javascript:viewBackupCodes()'>резервные коды</a>";
"two_factor_authentication_disabled_message" = "Двухфакторная аутентификация отключена";
"view_backup_codes" = "Посмотреть резервные коды";
"backup_codes" = "Резервные коды для подтверждения входа";
"two_factor_authentication_backup_codes_1" = "Резервные коды позволяют подтверждать вход, когда у вас нет доступа к телефону, например, в путешествии.";
"two_factor_authentication_backup_codes_2" = "У вас есть ещё <b>10 кодов</b>, каждым кодом можно воспользоваться только один раз. Распечатайте их, уберите в надежное место и используйте, когда потребуются коды для подтверждения входа.";
"two_factor_authentication_backup_codes_3" = "Вы можете получить новые коды, если они заканчиваются. Действительны только последние созданные резервные коды.";
/* Sorting */
"sort_randomly" = "Сортировать случайно";
"sort_up" = "Сортировать по дате создания вверх";
"sort_down" = "Сортировать по дате создания вниз";
/* Videos */
"videos" = "Видеозапись";
"video" = "Видеозапись";
"upload_video" = "Ватсаны видео";
"video_uploaded" = "Ватсаны";
"video_updated" = "- лэн выльдэм";
"video_link_to_yt" = "вылэ Ссылка YouTube";
"info_name" = "Нимыза";
"info_description" = "Кылсуред";
"info_uploaded_by" = "Ватсаны";
"info_upload_date" = "загрузка Дыр";
"videos_zero" = "одӥг но видеозапись";
"videos_one" = "Одӥг видеозапись";
"videos_few" = "$1 видеозапись";
"videos_many" = "$1 видеозапись";
"videos_other" = "$1 видеозапись";
/* Notifications */
"feedback" = "Ответ";
"unread" = "Непрочитанный";
"archive" = "Архив";
"notifications_like" = "$1 тон дунъяны $2 гожъямъёсыз$3 $4";
"notifications_repost" = "$1 paylaş(-лася) тон $2 гожъямъёсыз$3 $4";
"notifications_comment_under" = "$1 кельтыса(-ла) улэ комментарий $2";
"notifications_under_note" = "тон $3заметкой$4";
"notifications_under_photo" = "тон $туспуктэм 3$4";
"notifications_under_post" = "тон $гожъян 3$4 $5 - лы";
"notifications_under_video" = "тон $video 3$4";
"notifications_post" = "$1 гожтэ(-ла) $2 гожъямъёсыз$борддоръёсыз вылэ-тонэ 3: $4";
"notifications_appoint" = "$1 сообщество тон дасямын кивалтӥсез $2";
"nt_liked_yours" = "тыныд кельше";
"nt_shared_yours" = "paylaş(-аса) тон";
"nt_commented_yours" = "кельты(а) комментарий улын";
"nt_written_on_your_wall" = "гожтыны(а) ас вылэ борддор";
"nt_made_you_admin" = "висъяськы(нош) тон кивалтӥсез сообщество";
"nt_from" = "дор";
"nt_yours_adjective" = "тон";
"nt_yours_feminitive_adjective" = "тон";
"nt_post_nominative" = "кӧс";
"nt_post_instrumental" = "кӧс";
"nt_note_instrumental" = "заметка";
"nt_photo_instrumental" = "туспуктэмъёс";
"nt_topic_instrumental" = "темая";
/* Time */
"time_at_sp" = " ын ";
"time_just_now" = "гинэ мар";
"time_exactly_five_minutes_ago" = "5 минутлы азьло ӵапак";
"time_minutes_ago" = "$1 минутэ учке";
"time_today" = "туннэ";
"time_yesterday" = "толон";
"points" = "Голоса";
"points_count" = "голосов";
"on_your_account" = "на вашем счету";
"vouchers" = "Ваучеръёсты";
"have_voucher" = "Вал, ваучеръёсты";
"voucher_token" = "Кода ваучеръёсты";
"voucher_activators" = "Бен";
"voucher_explanation" = "ваучеръёс серийный номеръёс пыртылэмын. Ӵогын яке огшоры верам соосыз возьмало.";
"voucher_explanation_ex" = "учкы, мар со луыны быгатоз одӥг пол гинэ но ваучеръёсмес луонлык быриз.";
"invalid_voucher" = "недействительный ваучеръёсты";
"voucher_bad" = "оло, тӥ пыр серийный номерзэ шонертэм, бырыны-а сётэм яке со ваучеръёсыз огшоры ик кутэ ини.";
"voucher_good" = "активировать ваучеръёсты";
"voucher_redeemed" = "активировать Ваучеръёс-йыг вал. Тон куара начислить карем вал, уг быгаты тынэсьтыд сое но та активировать кода.";
"redeem" = "Активировать ваучеръёсты";
"deactivate" = "Деактивировать";
"usages_total" = "ужатонъя лыд";
"usages_left" = "Кылем ужатонъя";
"points_transfer_dialog_header_1" = "Вы можете отправить в подарок или передать часть голосов другому человеку.";
"points_transfer_dialog_header_2" = "Ваш текущий баланс:";
"points_amount_one" = "1 голос";
"points_amount_few" = "$1 голоса";
"points_amount_many" = "$1 голосов";
"points_amount_other" = "$1 голосов";
"transfer_poins" = "Передача голосов";
"transfer_poins_button" = "Передать голоса";
"also_you_can_transfer_points" = "Также вы можете <a href=\"javascript:showCoinsTransferDialog($1, '$2')\">передать голоса</a> другому человеку.";
"transferred_to_you" = "передал вам";
"receiver_address" = "Адрес получателя";
"coins_count" = "Количество голосов";
"message" = "Сообщение";
"failed_to_tranfer_points" = "Не удалось передать голоса";
"points_transfer_successful" = "Вы успешно передали <b>$1 <a href=\"$2\">$3</a></b>.";
"not_all_information_has_been_entered" = "Введена не вся информация.";
"negative_transfer_value" = "Мы не можем украсть голоса у другого человека, извините.";
"message_is_too_long" = "Сообщение слишком длинное.";
"receiver_not_found" = "Получатель не найден.";
"you_dont_have_enough_points" = "У вас недостаточно голосов.";
/* Gifts */
"gift" = "Кузьым";
"gifts" = "Кузьым";
"gifts_zero" = "кузьым Ӧвӧл";
"gifts_one" = "одӥг кузьым";
"gifts_few" = "$1 кузьым";
"gifts_many" = "$1 кузьым";
"gifts_other" = "$1 кузьым";
"gifts_left" = "Кузьым кыльы: $1";
"gifts_left_one" = "кылиз одӥг кузьым";
"gifts_left_few" = "$1 кылем кузьым";
"gifts_left_menu" = "$1 кылем кузьым";
"gifts_left_other" = "$1 кылем кузьым";
"send_gift" = "Отправить подарок";
"gift_select" = "Выбрать подарок";
"collections" = "Коллекции";
"confirm" = "Подтверждение";
"as_anonymous" = "Анонимно";
"gift_your_message" = "Ваше сообщение";
"free_gift" = "Бесплатно";
"coins" = "Голоса";
"coins_zero" = "0 голосов";
"coins_one" = "Один голос";
"coins_few" = "$1 голоса";
"coins_many" = "$1 голосов";
"coins_other" = "$1 голосов";
"users_gifts" = "Подарки";
/* Support */
"support_opened" = "Буш";
"support_answered" = "Ӵош ответ";
"support_closed" = "Ворсамын";
"support_ticket" = "Обращениез";
"support_tickets" = "Обращениез";
"support_status_0" = "Юан эскеремын";
"support_status_1" = "Луэ ответ";
"support_status_2" = "Ворсамын";
"support_greeting_hi" = "ӟеч-а, бур - $1!";
"support_greeting_regards" = "гажамысь,<br/>команда юрттэт $1.";
"support_faq" = "Часто задаваемые вопросы";
"support_list" = "Список обращений";
"support_new" = "Новое обращение";
"support_faq_title" = "Для кого этот сайт?";
"support_faq_content" = "Сайт предназначен для поиска друзей и знакомых, а также для просмотра данных пользователя. Это как справочник города, с помощью которого люди могут быстро найти актуальную информацию о человеке.";
"support_new_title" = "Темая-лэсь вазиськонэ пыртӥзы";
"support_new_content" = "Гожтэмын яке предложениосты ужпум";
"support_rate_good_answer" = "та умой ответ";
"support_rate_bad_answer" = "уродзэ та ответ";
"support_good_answer_user" = "положительной отзыв тон кельты.";
"support_bad_answer_user" = "негативный отзыв тон кельты.";
"support_good_answer_agent" = "Пользователь кельто положительной отзыв";
"support_bad_answer_agent" = "Пользователь негативный кельто отзыв";
"support_rated_good" = "тон сярысь веранзэ азьланьтэ отзыв кельто.";
"support_rated_bad" = "тыныд ответ кельто негативный сярысь отзывъёссэс.";
"wrong_parameters" = "запрос параметръёсты оскытылӥзы.";
"fast_answers" = "Быстрые ответы";
"comment" = "Комментарий";
"sender" = "Отправитель";
"author" = "Автор";
"you_have_not_entered_text" = "Вы не ввели текст";
"you_have_not_entered_name_or_text" = "Вы не ввели имя или текст";
"ticket_changed" = "Тикет изменён";
"ticket_changed_comment" = "Изменения вступят силу через несколько секунд.";
/* Invite */
"invite" = "Пригласить";
"you_can_invite" = "Вы можете пригласить своих друзей или знакомых в сеть с помощью индивидуальной ссылки:";
"you_can_invite_2" = "Приложите эту ссылку к вашему сообщению. Пользователь зарегистрируется, и он сразу появится у вас в друзьях.";
/* Banned */
"banned_title" = "Вам бан";
"banned_header" = "Вы были верискокнуты";
"banned_alt" = "Пользователь заблокирован.";
"banned_1" = "Извините, <b>$1</b>, но вы были верискокнуты.";
"banned_2" = "А причина этому проста: <b>$1</b>. К сожалению, на этот раз нам пришлось заблокировать вас навсегда.";
"banned_3" = "Вы всё ещё можете <a href=\"/support?act=new\">написать в службу поддержки</a>, если считаете что произошла ошибка или <a href=\"/logout?hash=$1\">выйти</a>.";
/* Discussions */
"discussions" = "Обсуждения";
"messages_one" = "Одно сообщение";
"messages_few" = "$1 сообщения";
"messages_many" = "$1 сообщений";
"messages_other" = "$1 сообщений";
"topic_messages_count_zero" = "В теме нет сообщений";
"topic_messages_count_one" = "В теме одно сообщение";
"topic_messages_count_few" = "В теме $1 сообщения";
"topic_messages_count_many" = "В теме $1 сообщений";
"topic_messages_count_other" = "В теме $1 сообщений";
"replied" = "ответил";
"create_topic" = "Кылдӥз тему";
"new_topic" = "Новая тема";
"title" = "Заголовок";
"text" = "Текст";
"view_topic" = "Просмотр темы";
"edit_topic_action" = "Редактировать тему";
"edit_topic" = "Редактирование темы";
"topic_settings" = "Настройки темы";
"pin_topic" = "Закрепить тему";
"close_topic" = "Закрыть тему";
"delete_topic" = "Удалить тему";
"topics_one" = "Одна тема";
"topics_few" = "$1 темы";
"topics_many" = "$1 тема";
"topics_other" = "$1 тем";
"created" = "Создано";
"everyone_can_create_topics" = "Все могут создавать темы";
"display_list_of_topics_above_wall" = "Отображать список тем над стеной";
"topic_changes_saved_comment" = "Обновлённый заголовок и настройки появятся на странице с темой.";
"failed_to_create_topic" = "Не удалось кылдӥз тему";
"failed_to_change_topic" = "Не удалось изменить тему";
"no_title_specified" = "Заголовок не указан.";
/* Errors */
"error_1" = "Некорректный запрос";
"error_2" = "Логин пароль яке Мыдлань";
"error_3" = "Уг авторизовать";
"error_4" = "уг уло Пользователь";
"information_-1" = "операциосты быдэсъяны йыг";
"information_-2" = "йыг пырон быдэстэм";
"no_data" = "Нет данных";
"no_data_description" = "Ивортодэт татын ӧвӧл татын.";
"error" = "Янгыше";
"error_shorturl" = "Данный короткий адрес уже занят.";
"error_segmentation" = "Янгышъёс сегментация";
"error_upload_failed" = "Не удалось загрузить фото";
"error_old_password" = "Старый пароль не совпадает";
"error_new_password" = "Новые пароли не совпадает";
"error_shorturl_incorrect" = "Короткий адрес имеет некорректный формат.";
"error_repost_fail" = "Не удалось поделиться записью";
"forbidden" = "Ошибка доступа";
"forbidden_comment" = "Настройки приватности этого пользователя не разрешают вам смотреть на его страницу.";
"changes_saved" = "Изменения сохранены";
"changes_saved_comment" = "Новый данные появятся на вашей странице";
"photo_saved" = "Фотография сохранена";
"photo_saved_comment" = "Новое изображние профиля появится у вас на странице";
"shared_succ" = "Запись появится на вашей стене. Нажмите на уведомление, чтобы перейти к своей стене.";
"invalid_email_address" = "Неверный Email адрес";
"invalid_email_address_comment" = "Email, который вы ввели, не является корректным.";
"invalid_telegram_name" = "Неверное имя Telegram аккаунта";
"invalid_telegram_name_comment" = "Вы ввели неверное имя аккаунта Telegram.";
"invalid_birth_date" = "Неверная дата рождения";
"invalid_birth_date_comment" = "Дата рождения, которую вы ввели, не является корректной.";
"token_manipulation_error" = "Ошибка манипулирования токеном";
"token_manipulation_error_comment" = "Токен недействителен или истёк";
"profile_changed" = "Профиль изменён";
"profile_changed_comment" = "Ваш активный профиль был изменён.";
"profile_not_found" = "Пользователь не найден.";
"suspicious_registration_attempt" = "Подозрительная попытка регистрации";
"suspicious_registration_attempt_comment" = "Вы пытались зарегистрироваться из подозрительного места.";
"rate_limit_error" = "Чумба, ты совсем ёбнутый?";
"rate_limit_error_comment" = "Сходи к мозгоправу, попей колёсики. В $1 нельзя вбрасывать щитпосты так часто. Код исключения: $2.";
"not_enough_permissions" = "Недостаточно прав";
"not_enough_permissions_comment" = "У вас недостаточно прав чтобы выполнять это действие.";
"login_required_error" = "Недостаточно прав";
"login_required_error_comment" = "Чтобы просматривать эту страницу, нужно зайти на сайт.";
"captcha_error" = "Неправильно введены символы";
"captcha_error_comment" = "Пожалуйста, убедитесь, что вы правильно заполнили поле с капчей.";
/* Admin actions */
"login_as" = "кызьы пыриды $1";
"manage_user_action" = "граждан Управление";
"manage_group_action" = "клуб Управление";
"ban_user_action" = "граждан Заблокировать";
"warn_user_action" = "граждан Шӧдытыны";
/* Paginator (deprecated) */
"paginator_back" = "Берлань";
"paginator_page" = "Бам $1";
"paginator_next" = "Кыдёке";
/* About */
"about_openvk" = "Сярысь органъёс OpenVK";
/* Dialogs */
"ok" = "ӜОГ";
"yes" = "Я";
"no" = "Ӧвӧл";
"cancel" = "Воштон";
"edit_action" = "Воштоз";
"transfer" = "Дышетон";
"close" = "Ворсамын";
"warning" = "Айкай";
"question_confirm" = "Та ужме уг вошты. Зэм но, мар каремзы потэ, тон солы оскиськод-а?";
/* User alerts */
"user_alert_scam" = "мошенничество тросгес герӟаськемын та to вылэ ӝожтӥсько. Пожалуйста, сак луыны, уката ик дорын тонэ уксё куре ке.";

View file

@ -59,6 +59,7 @@ openvk:
bellsAndWhistles:
fartscroll: false
testLabel: false
defaultMobileTheme: ""
telemetry:
plausible:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -15,6 +15,13 @@ body {
background-position-x: 1px;
}
.home_button_custom {
background: url("/themepack/openvk_modern/0.0.1.0/resource/5.png") no-repeat;
background-position-y: 0px;
background-position-x: 1px;
text-shadow: none;
}
.header_navigation .link {
background: unset;
}