mirror of
https://github.com/openvk/openvk
synced 2025-07-08 16:53:02 +03:00
Merge branch 'openvk:master' into master
This commit is contained in:
commit
8ee1d8749d
31 changed files with 454 additions and 151 deletions
|
@ -324,7 +324,7 @@ class User extends RowModel
|
|||
|
||||
function getAge(): ?int
|
||||
{
|
||||
return (int)floor((time() - $this->getBirthday()->timestamp()) / mktime(0, 0, 0, 1, 1, 1971));
|
||||
return (int)floor((time() - $this->getBirthday()->timestamp()) / YEAR);
|
||||
}
|
||||
|
||||
function get2faSecret(): ?string
|
||||
|
@ -372,6 +372,7 @@ class User extends RowModel
|
|||
"friends.read",
|
||||
"friends.add",
|
||||
"wall.write",
|
||||
"messages.write",
|
||||
],
|
||||
])->get($id);
|
||||
}
|
||||
|
@ -540,6 +541,8 @@ class User extends RowModel
|
|||
$manager = $club->getManager($this);
|
||||
if(!is_null($manager))
|
||||
return $manager->isClubPinned();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getMeetings(int $page = 1): \Traversable
|
||||
|
@ -696,16 +699,18 @@ class User extends RowModel
|
|||
]);
|
||||
}
|
||||
|
||||
function ban(string $reason): void
|
||||
function ban(string $reason, bool $deleteSubscriptions = true): void
|
||||
{
|
||||
$subs = DatabaseConnection::i()->getContext()->table("subscriptions");
|
||||
$subs = $subs->where(
|
||||
"follower = ? OR (target = ? AND model = ?)",
|
||||
$this->getId(),
|
||||
$this->getId(),
|
||||
get_class($this),
|
||||
);
|
||||
$subs->delete();
|
||||
if($deleteSubscriptions) {
|
||||
$subs = DatabaseConnection::i()->getContext()->table("subscriptions");
|
||||
$subs = $subs->where(
|
||||
"follower = ? OR (target = ? AND model = ?)",
|
||||
$this->getId(),
|
||||
$this->getId(),
|
||||
get_class($this),
|
||||
);
|
||||
$subs->delete();
|
||||
}
|
||||
|
||||
$this->setBlock_Reason($reason);
|
||||
$this->save();
|
||||
|
@ -752,6 +757,7 @@ class User extends RowModel
|
|||
"friends.read",
|
||||
"friends.add",
|
||||
"wall.write",
|
||||
"messages.write",
|
||||
],
|
||||
])->set($id, $status)->toInteger());
|
||||
}
|
||||
|
|
|
@ -83,4 +83,37 @@ final class AboutPresenter extends OpenVKPresenter
|
|||
{
|
||||
$this->template->languages = getLanguages();
|
||||
}
|
||||
|
||||
function renderRobotsTxt(): void
|
||||
{
|
||||
$text = "# robots.txt file for openvk\n"
|
||||
. "#\n"
|
||||
. "# this includes only those links that are not in any way\n"
|
||||
. "# covered from unauthorized persons (for example, due to\n"
|
||||
. "# lack of rights to access the admin panel)\n\n"
|
||||
. "User-Agent: *\n"
|
||||
. "Disallow: /rpc\n"
|
||||
. "Disallow: /language\n"
|
||||
. "Disallow: /badbrowser.php\n"
|
||||
. "Disallow: /logout\n"
|
||||
. "Disallow: /away.php\n"
|
||||
. "Disallow: /im?\n"
|
||||
. "Disallow: *query=\n"
|
||||
. "Disallow: *?lg=\n"
|
||||
. "Disallow: *hash=\n"
|
||||
. "Disallow: *?jReturnTo=\n"
|
||||
. "Disallow: /method/*\n"
|
||||
. "Disallow: /token*";
|
||||
header("Content-Type: text/plain");
|
||||
exit($text);
|
||||
}
|
||||
|
||||
function renderHumansTxt(): void
|
||||
{
|
||||
// :D
|
||||
|
||||
header("HTTP/1.1 302 Found");
|
||||
header("Location: https://github.com/openvk/openvk#readme");
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -219,10 +219,17 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
if($_FILES["ava"]["error"] === UPLOAD_ERR_OK) {
|
||||
$photo = new Photo;
|
||||
try {
|
||||
$anon = OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["enable"];
|
||||
if($anon && $this->user->id === $club->getOwner()->getId())
|
||||
$anon = $club->isOwnerHidden();
|
||||
else if($anon)
|
||||
$anon = $club->getManager($this->user->identity)->isHidden();
|
||||
|
||||
$photo->setOwner($this->user->id);
|
||||
$photo->setDescription("Profile image");
|
||||
$photo->setFile($_FILES["ava"]);
|
||||
$photo->setCreated(time());
|
||||
$photo->setAnonymous($anon);
|
||||
$photo->save();
|
||||
|
||||
(new Albums)->getClubAvatarAlbum($club)->addPhoto($photo);
|
||||
|
|
|
@ -124,7 +124,7 @@ final class MessengerPresenter extends OpenVKPresenter
|
|||
}
|
||||
|
||||
$sel = $this->getCorrespondent($sel);
|
||||
if($sel->getId() !== $this->user->id && $sel->getSubscriptionStatus($this->user->identity) !== 3)
|
||||
if($sel->getId() !== $this->user->id && !$sel->getPrivacyPermission('messages.write', $this->user->identity))
|
||||
exit(header("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
$cor = new Correspondence($this->user->identity, $sel);
|
||||
|
|
|
@ -39,14 +39,26 @@ abstract class OpenVKPresenter extends SimplePresenter
|
|||
Session::i()->set("_tempTheme", $theme);
|
||||
}
|
||||
|
||||
protected function flashFail(string $type, string $title, ?string $message = NULL, ?int $code = NULL): void
|
||||
protected function flashFail(string $type, string $title, ?string $message = NULL, ?int $code = NULL, bool $json = false): void
|
||||
{
|
||||
$this->flash($type, $title, $message, $code);
|
||||
$referer = $_SERVER["HTTP_REFERER"] ?? "/";
|
||||
if($json) {
|
||||
$this->returnJson([
|
||||
"success" => $type !== "err",
|
||||
"flash" => [
|
||||
"type" => $type,
|
||||
"title" => $title,
|
||||
"message" => $message,
|
||||
"code" => $code,
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
$this->flash($type, $title, $message, $code);
|
||||
$referer = $_SERVER["HTTP_REFERER"] ?? "/";
|
||||
|
||||
header("HTTP/1.1 302 Found");
|
||||
header("Location: $referer");
|
||||
exit;
|
||||
header("HTTP/1.1 302 Found");
|
||||
header("Location: $referer");
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
protected function logInUserWithToken(): void
|
||||
|
@ -120,18 +132,18 @@ abstract class OpenVKPresenter extends SimplePresenter
|
|||
$this->flashFail("err", tr("captcha_error"), tr("captcha_error_comment"));
|
||||
}
|
||||
|
||||
protected function willExecuteWriteAction(): void
|
||||
protected function willExecuteWriteAction(bool $json = false): void
|
||||
{
|
||||
$ip = (new IPs)->get(CONNECTING_IP);
|
||||
$res = $ip->rateLimit();
|
||||
|
||||
if(!($res === IP::RL_RESET || $res === IP::RL_CANEXEC)) {
|
||||
if($res === IP::RL_BANNED && OPENVK_ROOT_CONF["openvk"]["preferences"]["security"]["rateLimits"]["autoban"]) {
|
||||
$this->user->identity->ban("Account has possibly been stolen");
|
||||
$this->user->identity->ban("Account has possibly been stolen", false);
|
||||
exit("Хакеры? Интересно...");
|
||||
}
|
||||
|
||||
$this->flashFail("err", tr("rate_limit_error"), tr("rate_limit_error_comment", OPENVK_ROOT_CONF["openvk"]["appearance"]["name"], $res));
|
||||
$this->flashFail("err", tr("rate_limit_error"), tr("rate_limit_error_comment", OPENVK_ROOT_CONF["openvk"]["appearance"]["name"], $res), NULL, $json);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,4 +253,13 @@ abstract class OpenVKPresenter extends SimplePresenter
|
|||
Session::i()->set("_error", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
protected function returnJson(array $json): void
|
||||
{
|
||||
$payload = json_encode($json);
|
||||
$size = strlen($payload);
|
||||
header("Content-Type: application/json");
|
||||
header("Content-Length: $size");
|
||||
exit($payload);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -164,9 +164,10 @@ final class SupportPresenter extends OpenVKPresenter
|
|||
$this->notFound();
|
||||
|
||||
$ticketComments = $this->comments->getCommentsById($id);
|
||||
$this->template->ticket = $ticket;
|
||||
$this->template->comments = $ticketComments;
|
||||
$this->template->id = $id;
|
||||
$this->template->ticket = $ticket;
|
||||
$this->template->comments = $ticketComments;
|
||||
$this->template->id = $id;
|
||||
$this->template->fastAnswers = OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["fastAnswers"];
|
||||
}
|
||||
|
||||
function renderAnswerTicketReply(int $id): void
|
||||
|
|
|
@ -87,7 +87,7 @@ final class UserPresenter extends OpenVKPresenter
|
|||
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment"));
|
||||
else {
|
||||
$this->template->user = $user;
|
||||
$this->template->page = $this->queryParam("p") ?? 1;
|
||||
$this->template->page = (int) ($this->queryParam("p") ?? 1);
|
||||
$this->template->admin = $this->queryParam("act") == "managed";
|
||||
}
|
||||
}
|
||||
|
@ -101,11 +101,11 @@ final class UserPresenter extends OpenVKPresenter
|
|||
$this->notFound();
|
||||
|
||||
if(!$club->canBeModifiedBy($this->user->identity ?? NULL))
|
||||
$this->flashFail("err", "Ошибка доступа", "У вас недостаточно прав, чтобы изменять этот ресурс.");
|
||||
$this->flashFail("err", "Ошибка доступа", "У вас недостаточно прав, чтобы изменять этот ресурс.", NULL, true);
|
||||
|
||||
$isClubPinned = $this->user->identity->isClubPinned($club);
|
||||
if(!$isClubPinned && $this->user->identity->getPinnedClubCount() > 10)
|
||||
$this->flashFail("err", "Ошибка", "Находится в левом меню могут максимум 10 групп");
|
||||
$this->flashFail("err", "Ошибка", "Находится в левом меню могут максимум 10 групп", NULL, true);
|
||||
|
||||
if($club->getOwner()->getId() === $this->user->identity->getId()) {
|
||||
$club->setOwner_Club_Pinned(!$isClubPinned);
|
||||
|
@ -118,10 +118,9 @@ final class UserPresenter extends OpenVKPresenter
|
|||
}
|
||||
}
|
||||
|
||||
if($isClubPinned)
|
||||
$this->flashFail("succ", "Операция успешна", "Группа " . $club->getName() . " была успешно удалена из левого меню");
|
||||
else
|
||||
$this->flashFail("succ", "Операция успешна", "Группа " . $club->getName() . " была успешно добавлена в левое меню");
|
||||
$this->returnJson([
|
||||
"success" => true
|
||||
]);
|
||||
}
|
||||
|
||||
function renderEdit(): void
|
||||
|
@ -135,7 +134,7 @@ final class UserPresenter extends OpenVKPresenter
|
|||
|
||||
$user = $this->users->get($id);
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$this->willExecuteWriteAction();
|
||||
$this->willExecuteWriteAction($_GET['act'] === "status");
|
||||
|
||||
if($_GET['act'] === "main" || $_GET['act'] == NULL) {
|
||||
$user->setFirst_Name(empty($this->postParam("first_name")) ? $user->getFirstName() : $this->postParam("first_name"));
|
||||
|
@ -197,15 +196,15 @@ final class UserPresenter extends OpenVKPresenter
|
|||
} elseif($_GET['act'] === "status") {
|
||||
if(mb_strlen($this->postParam("status")) > 255) {
|
||||
$statusLength = (string) mb_strlen($this->postParam("status"));
|
||||
$this->flashFail("err", "Ошибка", "Статус слишком длинный ($statusLength символов вместо 255 символов)");
|
||||
$this->flashFail("err", "Ошибка", "Статус слишком длинный ($statusLength символов вместо 255 символов)", NULL, true);
|
||||
}
|
||||
|
||||
$user->setStatus(empty($this->postParam("status")) ? NULL : $this->postParam("status"));
|
||||
$user->save();
|
||||
|
||||
header("HTTP/1.1 302 Found");
|
||||
header("Location: /id" . $user->getId());
|
||||
exit;
|
||||
$this->returnJson([
|
||||
"success" => true
|
||||
]);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -330,6 +329,7 @@ final class UserPresenter extends OpenVKPresenter
|
|||
"friends.read",
|
||||
"friends.add",
|
||||
"wall.write",
|
||||
"messages.write",
|
||||
];
|
||||
foreach($settings as $setting) {
|
||||
$input = $this->postParam(str_replace(".", "_", $setting));
|
||||
|
|
|
@ -320,7 +320,7 @@ final class WallPresenter extends OpenVKPresenter
|
|||
(new RepostNotification($post->getOwner(false), $post, $this->user->identity))->emit();
|
||||
};
|
||||
|
||||
exit(json_encode(["wall_owner" => $this->user->identity->getId()]));
|
||||
$this->returnJson(["wall_owner" => $this->user->identity->getId()]);
|
||||
}
|
||||
|
||||
function renderDelete(int $wall, int $post_id): void
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
{block content}
|
||||
<div class="navigation">
|
||||
{foreach $languages as $language}
|
||||
<a href="language?lg={$language['code']}&hash={urlencode($csrfToken)}" class="link"><img src="/assets/packages/static/openvk/img/flags/{$language['flag']}.gif"> {$language['native_name']}</a>
|
||||
<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}
|
||||
</div>
|
||||
{/block}
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
<span>{_"surname"}: </span>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="last_name" required />
|
||||
<input type="text" name="last_name" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
@ -91,13 +91,18 @@
|
|||
{presenter "openvk!Wall->wallEmbedded", -$club->getId()}
|
||||
</div>
|
||||
<div class="right_small_block">
|
||||
<a href="{$club->getAvatarLink()|nocheck}">
|
||||
{var avatarPhoto = $club->getAvatarPhoto()}
|
||||
{var avatarLink = ((is_null($avatarPhoto) ? FALSE : $avatarPhoto->isAnonymous()) ? "/photo" . ("s/" . base_convert((string) $avatarPhoto->getId(), 10, 32)) : $club->getAvatarLink())}
|
||||
<a href="{$avatarLink|nocheck}">
|
||||
<img src="{$club->getAvatarUrl()}" style="width: 100%; image-rendering: -webkit-optimize-contrast;" />
|
||||
</a>
|
||||
<div n:ifset="$thisUser" id="profile_links">
|
||||
{if $club->canBeModifiedBy($thisUser)}
|
||||
<a href="/club{$club->getId()}/edit" id="profile_link">{_"edit_group"}</a>
|
||||
{/if}
|
||||
{if $thisUser->getChandlerUser()->can("access")->model("admin")->whichBelongsTo(NULL)}
|
||||
<a href="/admin/clubs/id{$club->getId()}" id="profile_link">{_"manage_group_action"}</a>
|
||||
{/if}
|
||||
{if $club->getSubscriptionStatus($thisUser) == false}
|
||||
<form action="/setSub/club" method="post">
|
||||
<input type="hidden" name="act" value="add" />
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="messenger-app--input">
|
||||
{if $correspondent->getId() === $thisUser->getId() || ($correspondent->getSubscriptionStatus($thisUser) === 3)}
|
||||
{if $correspondent->getId() === $thisUser->getId() || $correspondent->getPrivacyPermission('messages.write', $thisUser)}
|
||||
<img class="ava" src="{$thisUser->getAvatarUrl()}" alt="{$thisUser->getCanonicalName()}" />
|
||||
<div class="messenger-app--input---messagebox">
|
||||
<textarea
|
||||
|
@ -54,7 +54,7 @@
|
|||
</div>
|
||||
<img class="ava" src="{$correspondent->getAvatarUrl()}" alt="{$correspondent->getCanonicalName()}" />
|
||||
{else}
|
||||
<div class="blocked" data-localized-text="Вы не можете писать сообщения {$correspondent->getCanonicalName()}, так как его нет в вашем списке друзей."></div>
|
||||
<div class="blocked" data-localized-text="Вы не можете писать сообщения {$correspondent->getCanonicalName()} из-за его настроек приватности."></div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -24,18 +24,24 @@
|
|||
</div><br/>
|
||||
<div>
|
||||
<form action="/al_comments.pl/create/support/reply/{$id}" method="post" style="margin:0;">
|
||||
<textarea name="text" style="width: 100%;resize: vertical;"></textarea>
|
||||
<textarea name="text" id="answer_text" style="width: 100%;resize: vertical;"></textarea>
|
||||
<div>
|
||||
<!-- padding to fix <br/> bug -->
|
||||
</div>
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
<br>
|
||||
<input type="submit" value="{_write}" class="button">
|
||||
<select name="status" style="width: unset;">
|
||||
<option value="1">{_support_status_1}</option>
|
||||
<option value="2">{_support_status_2}</option>
|
||||
<option value="0">{_support_status_0}</option>
|
||||
</select>
|
||||
<br />
|
||||
<div style="float: left;">
|
||||
<input type="submit" value="{_write}" class="button">
|
||||
<select name="status" style="width: unset;">
|
||||
<option value="1">{_support_status_1}</option>
|
||||
<option value="2">{_support_status_2}</option>
|
||||
<option value="0">{_support_status_0}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div n:if="!is_null($fastAnswers)" style="float: right;">
|
||||
<a class="button" href="javascript:showSupportFastAnswerDialog(fastAnswers)">{_fast_answers}</a>
|
||||
</div>
|
||||
<br />
|
||||
</form>
|
||||
</div>
|
||||
<br/>
|
||||
|
@ -126,4 +132,12 @@
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
const fastAnswers = [
|
||||
{foreach $fastAnswers as $answer}
|
||||
{$answer},
|
||||
{/foreach}
|
||||
];
|
||||
</script>
|
||||
{/block}
|
||||
|
|
|
@ -51,9 +51,9 @@
|
|||
{$x->getDescription()}
|
||||
{/block}
|
||||
|
||||
{var clubPinned = $thisUser->isClubPinned($x)}
|
||||
{if $x->canBeModifiedBy($thisUser ?? NULL) || $clubPinned || $thisUser->getPinnedClubCount() <= 10}
|
||||
{block actions}
|
||||
{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()}">
|
||||
{if $clubPinned}
|
||||
{_remove_from_left_menu}
|
||||
|
@ -61,5 +61,5 @@
|
|||
{_add_to_left_menu}
|
||||
{/if}
|
||||
</a>
|
||||
{/block}
|
||||
{/if}
|
||||
{/if}
|
||||
{/block}
|
||||
|
|
|
@ -316,6 +316,18 @@
|
|||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="120" valign="top">
|
||||
<span class="nobold">{_privacy_setting_write_messages}</span>
|
||||
</td>
|
||||
<td>
|
||||
<select name="messages.write", style="width: 164px;">
|
||||
<option value="2" {if $user->getPrivacySetting('messages.write') == 2}selected{/if}>{_privacy_value_anybody}</option>
|
||||
<option value="1" {if $user->getPrivacySetting('messages.write') == 1}selected{/if}>{_privacy_value_friends}</option>
|
||||
<option value="0" {if $user->getPrivacySetting('messages.write') == 0}selected{/if}>{_privacy_value_nobody}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
|
@ -348,16 +360,40 @@
|
|||
{elseif $isFinanceTU}
|
||||
|
||||
<p>{_voucher_explanation} {_voucher_explanation_ex}</p>
|
||||
<form action="/settings?act=finance.top-up" method="POST" enctype="multipart/form-data">
|
||||
<input type="text" name="key0" size="6" placeholder="123456" required="required" style="display: inline-block; width: 50px; text-align: center;" /> -
|
||||
<input type="text" name="key1" size="6" placeholder="789012" required="required" style="display: inline-block; width: 50px; text-align: center;" /> -
|
||||
<input type="text" name="key2" size="6" placeholder="345678" required="required" style="display: inline-block; width: 50px; text-align: center;" /> -
|
||||
<input type="text" name="key3" size="6" placeholder="90ABCD" required="required" style="display: inline-block; width: 50px; text-align: center;" />
|
||||
<form name="vouncher_form" action="/settings?act=finance.top-up" method="POST" enctype="multipart/form-data">
|
||||
<input type="text" name="key0" class="vouncher_input" size="6" maxlength="6" placeholder="123456" required="required" oninput="autoTab(this, document.vouncher_form.key1, undefined)" style="display: inline-block; width: 50px; text-align: center;" /> -
|
||||
<input type="text" name="key1" class="vouncher_input" size="6" maxlength="6" placeholder="789012" required="required" oninput="autoTab(this, document.vouncher_form.key2, document.vouncher_form.key0)" style="display: inline-block; width: 50px; text-align: center;" /> -
|
||||
<input type="text" name="key2" class="vouncher_input" size="6" maxlength="6" placeholder="345678" required="required" oninput="autoTab(this, document.vouncher_form.key3, document.vouncher_form.key1)" style="display: inline-block; width: 50px; text-align: center;" /> -
|
||||
<input type="text" name="key3" class="vouncher_input" size="6" maxlength="6" placeholder="90ABCD" required="required" oninput="autoTab(this, undefined, document.vouncher_form.key2)" style="display: inline-block; width: 50px; text-align: center;" />
|
||||
<br/><br/>
|
||||
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
<input type="submit" value="{_redeem}" class="button" />
|
||||
</form>
|
||||
<script>
|
||||
u(".vouncher_input").on("paste", function(event) {
|
||||
const vouncher = event.clipboardData.getData("text");
|
||||
|
||||
let segments;
|
||||
if(vouncher.length === 27) {
|
||||
segments = vouncher.split("-");
|
||||
if(segments.length !== 4)
|
||||
segments = undefined;
|
||||
} else if(vouncher.length === 24) {
|
||||
segments = chunkSubstr(vouncher, 6);
|
||||
}
|
||||
|
||||
if(segments !== undefined) {
|
||||
document.vouncher_form.key0.value = segments[0];
|
||||
document.vouncher_form.key1.value = segments[1];
|
||||
document.vouncher_form.key2.value = segments[2];
|
||||
document.vouncher_form.key3.value = segments[3];
|
||||
document.vouncher_form.key3.focus();
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
});
|
||||
</script>
|
||||
|
||||
{elseif $isInterface}
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@
|
|||
{/if}
|
||||
|
||||
<a n:if="OPENVK_ROOT_CONF['openvk']['preferences']['commerce'] && $user->getGiftCount() == 0" href="/gifts?act=pick&user={$user->getId()}" class="profile_link">{_send_gift}</a>
|
||||
<a n:if="$user->getPrivacyPermission('messages.write', $thisUser)" href="/im?sel={$user->getId()}" class="profile_link">{_"send_message"}</a>
|
||||
|
||||
{var subStatus = $user->getSubscriptionStatus($thisUser)}
|
||||
{if $subStatus === 0}
|
||||
|
@ -116,7 +117,6 @@
|
|||
<input type="submit" class="profile_link" value="{_"friends_reject"}" />
|
||||
</form>
|
||||
{elseif $subStatus === 3}
|
||||
<a href="/im?sel={$user->getId()}" class="profile_link">{_"send_message"}</a>
|
||||
<form action="/setSub/user" method="post" class="profile_link_form">
|
||||
<input type="hidden" name="act" value="rem" />
|
||||
<input type="hidden" name="id" value="{$user->getId()}" />
|
||||
|
@ -313,15 +313,15 @@
|
|||
|
||||
<div class="right_big_block">
|
||||
<div class="page_info">
|
||||
<div n:if="!is_null($alert = $user->getAlert())" class="user-alert">{$alert}</div>
|
||||
<div n:if="!is_null($alert = $user->getAlert())" class="user-alert">{strpos($alert, "@") === 0 ? tr(substr($alert, 1)) : $alert}</div>
|
||||
{var thatIsThisUser = isset($thisUser) && $user->getId() == $thisUser->getId()}
|
||||
<div n:if="$thatIsThisUser" class="page_status_popup" id="status_editor" style="display: none;">
|
||||
<form method="post" action="/edit?act=status">
|
||||
<form name="status_popup_form" onsubmit="changeStatus(); return false;">
|
||||
<div style="margin-bottom: 10px;">
|
||||
<input type="text" name="status" size="50" value="{$user->getStatus()}" />
|
||||
</div>
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
<input type="submit" class="button" value="{_'save'}" />
|
||||
<button type="submit" name="submit" class="button" style="height: 22px;">{_send}</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="accountInfo clearFix">
|
||||
|
@ -543,9 +543,11 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<script n:if="isset($thisUser) && $user->getId() == $thisUser->getId()">
|
||||
<script n:if="isset($thisUser) && $user->getId() == $thisUser->getId()" n:syntax="off">
|
||||
function setStatusEditorShown(shown) {
|
||||
document.getElementById("status_editor").style.display = shown ? "block" : "none";
|
||||
if(!document.status_popup_form.submit.style.width)
|
||||
document.status_popup_form.submit.style.width = document.status_popup_form.submit.offsetWidth + 4 + "px"
|
||||
}
|
||||
|
||||
document.addEventListener("click", event => {
|
||||
|
@ -554,6 +556,36 @@
|
|||
});
|
||||
|
||||
document.getElementById("page_status_text").onclick = setStatusEditorShown.bind(this, true);
|
||||
|
||||
async function changeStatus() {
|
||||
const status = document.status_popup_form.status.value;
|
||||
|
||||
document.status_popup_form.submit.innerHTML = "<div class=\"button-loading\"></div>";
|
||||
document.status_popup_form.submit.disabled = true;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("status", status);
|
||||
formData.append("hash", document.status_popup_form.hash.value);
|
||||
const response = await ky.post("/edit?act=status", {body: formData});
|
||||
|
||||
if(!parseAjaxResponse(await response.text())) {
|
||||
document.status_popup_form.submit.innerHTML = tr("send");
|
||||
document.status_popup_form.submit.disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(document.status_popup_form.status.value === "") {
|
||||
document.querySelector("#page_status_text").innerHTML = `[ ${tr("change_status")} ]`;
|
||||
document.querySelector("#page_status_text").className = "edit_link page_status_edit_button";
|
||||
} else {
|
||||
document.querySelector("#page_status_text").innerHTML = status;
|
||||
document.querySelector("#page_status_text").className = "page_status page_status_edit_button";
|
||||
}
|
||||
|
||||
setStatusEditorShown(false);
|
||||
document.status_popup_form.submit.innerHTML = tr("send");
|
||||
document.status_popup_form.submit.disabled = false;
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -46,8 +46,8 @@
|
|||
});
|
||||
</script>
|
||||
</center>
|
||||
{/block}
|
||||
|
||||
{if isset($thisUser) && $thisUser->hasMicroblogEnabled()}
|
||||
{script "js/al_comments.js"}
|
||||
{/if}
|
||||
{if isset($thisUser) && $thisUser->hasMicroblogEnabled()}
|
||||
{script "js/al_comments.js"}
|
||||
{/if}
|
||||
{/block}
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
{/foreach}
|
||||
{include "../components/paginator.xml", conf => $paginatorConf}
|
||||
</center>
|
||||
{/block}
|
||||
|
||||
{if isset($thisUser) && $thisUser->hasMicroblogEnabled()}
|
||||
{script "js/al_comments.js"}
|
||||
{/if}
|
||||
{if isset($thisUser) && $thisUser->hasMicroblogEnabled()}
|
||||
{script "js/al_comments.js"}
|
||||
{/if}
|
||||
{/block}
|
||||
|
|
|
@ -13,28 +13,28 @@
|
|||
{/block}
|
||||
|
||||
{block content}
|
||||
<div class="content_divider">
|
||||
<div>
|
||||
<div n:if="$canPost" class="content_subtitle">
|
||||
{include "../components/textArea.xml", route => "/wall$owner/makePost"}
|
||||
</div>
|
||||
<div class="content_divider">
|
||||
<div>
|
||||
<div n:if="$canPost" class="content_subtitle">
|
||||
{include "../components/textArea.xml", route => "/wall$owner/makePost"}
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
{if sizeof($posts) > 0}
|
||||
{foreach $posts as $post}
|
||||
<a name="postGarter={$post->getId()}"></a>
|
||||
<div class="content">
|
||||
{if sizeof($posts) > 0}
|
||||
{foreach $posts as $post}
|
||||
<a name="postGarter={$post->getId()}"></a>
|
||||
|
||||
{include "../components/post.xml", post => $post, commentSection => true}
|
||||
{/foreach}
|
||||
{include "../components/paginator.xml", conf => $paginatorConf}
|
||||
{else}
|
||||
{_no_posts_abstract}
|
||||
{/if}
|
||||
{include "../components/post.xml", post => $post, commentSection => true}
|
||||
{/foreach}
|
||||
{include "../components/paginator.xml", conf => $paginatorConf}
|
||||
{else}
|
||||
{_no_posts_abstract}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{if isset($thisUser) && $thisUser->hasMicroblogEnabled()}
|
||||
{script "js/al_comments.js"}
|
||||
{/if}
|
||||
{if isset($thisUser) && $thisUser->hasMicroblogEnabled()}
|
||||
{script "js/al_comments.js"}
|
||||
{/if}
|
||||
{/block}
|
||||
|
|
|
@ -99,34 +99,40 @@
|
|||
{/if}
|
||||
|
||||
<div class="like_wrap">
|
||||
<a class="post-share-button" href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')">
|
||||
<div class="repost-icon" style="opacity: 0.4;"></div>
|
||||
<span class="likeCnt">{if $post->getRepostCount() > 0}{$post->getRepostCount()}{/if}</span>
|
||||
</a>
|
||||
{if !($forceNoShareLink ?? false)}
|
||||
<a class="post-share-button" href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')">
|
||||
<div class="repost-icon" style="opacity: 0.4;"></div>
|
||||
<span class="likeCnt">{if $post->getRepostCount() > 0}{$post->getRepostCount()}{/if}</span>
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
{var liked = $post->hasLikeFrom($thisUser)}
|
||||
<a href="/wall{$post->getPrettyId()}/like?hash={rawurlencode($csrfToken)}"
|
||||
class="post-like-button"
|
||||
data-liked="{(int) $liked}"
|
||||
data-likes="{$post->getLikesCount()}">
|
||||
<div class="heart" id="{if $liked}liked{/if}"></div>
|
||||
<span class="likeCnt">{if $post->getLikesCount() > 0}{$post->getLikesCount()}{/if}</span>
|
||||
</a>
|
||||
{if !($forceNoLike ?? false)}
|
||||
{var liked = $post->hasLikeFrom($thisUser)}
|
||||
<a href="/wall{$post->getPrettyId()}/like?hash={rawurlencode($csrfToken)}"
|
||||
class="post-like-button"
|
||||
data-liked="{(int) $liked}"
|
||||
data-likes="{$post->getLikesCount()}">
|
||||
<div class="heart" id="{if $liked}liked{/if}"></div>
|
||||
<span class="likeCnt">{if $post->getLikesCount() > 0}{$post->getLikesCount()}{/if}</span>
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div n:if="$commentSection == true && $compact == false" class="post-menu-s">
|
||||
{if $commentsCount > 3}
|
||||
<a href="/wall{$post->getPrettyId()}" class="expand_button">{_view_other_comments}</a>
|
||||
{/if}
|
||||
{foreach $comments as $comment}
|
||||
{include "../comment.xml", comment => $comment, $compact => true}
|
||||
{/foreach}
|
||||
<div n:ifset="$thisUser" id="commentTextArea{$commentTextAreaId}" n:attr="style => ($commentsCount == 0 ? 'display: none;')" class="commentsTextFieldWrap">
|
||||
{var commentsURL = "/al_comments.pl/create/posts/" . $post->getId()}
|
||||
{include "../textArea.xml", route => $commentsURL, postOpts => false, graffiti => (bool) ovkGetQuirk("comments.allow-graffiti"), post => $post}
|
||||
{if !($forceNoCommentsLink ?? false)}
|
||||
<div n:if="$commentSection == true && $compact == false" class="post-menu-s">
|
||||
{if $commentsCount > 3}
|
||||
<a href="/wall{$post->getPrettyId()}" class="expand_button">{_view_other_comments}</a>
|
||||
{/if}
|
||||
{foreach $comments as $comment}
|
||||
{include "../comment.xml", comment => $comment, $compact => true}
|
||||
{/foreach}
|
||||
<div n:ifset="$thisUser" id="commentTextArea{$commentTextAreaId}" n:attr="style => ($commentsCount == 0 ? 'display: none;')" class="commentsTextFieldWrap">
|
||||
{var commentsURL = "/al_comments.pl/create/posts/" . $post->getId()}
|
||||
{include "../textArea.xml", route => $commentsURL, postOpts => false, graffiti => (bool) ovkGetQuirk("comments.allow-graffiti"), post => $post}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -91,29 +91,35 @@
|
|||
{_"comments"}
|
||||
{/if}
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
{if !($forceNoCommentsLink ?? false) && !($forceNoShareLink ?? false)}
|
||||
|
|
||||
{/if}
|
||||
|
||||
<a class="post-share-button" href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')">
|
||||
{if $post->getRepostCount() > 0}
|
||||
{_"share"}
|
||||
(<b>{$post->getRepostCount()}</b>)
|
||||
{else}
|
||||
{_"share"}
|
||||
{/if}
|
||||
</a>
|
||||
|
||||
|
||||
<div class="like_wrap">
|
||||
{var liked = $post->hasLikeFrom($thisUser)}
|
||||
<a href="/wall{$post->getPrettyId()}/like?hash={rawurlencode($csrfToken)}"
|
||||
class="post-like-button"
|
||||
data-liked="{(int) $liked}"
|
||||
data-likes="{$post->getLikesCount()}">
|
||||
<div class="heart" id="{if $liked}liked{/if}"></div>
|
||||
<span class="likeCnt">{if $post->getLikesCount() > 0}{$post->getLikesCount()}{/if}</span>
|
||||
{if !($forceNoShareLink ?? false)}
|
||||
<a class="post-share-button" href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')">
|
||||
{if $post->getRepostCount() > 0}
|
||||
{_"share"}
|
||||
(<b>{$post->getRepostCount()}</b>)
|
||||
{else}
|
||||
{_"share"}
|
||||
{/if}
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{if !($forceNoLike ?? false)}
|
||||
<div class="like_wrap">
|
||||
{var liked = $post->hasLikeFrom($thisUser)}
|
||||
<a href="/wall{$post->getPrettyId()}/like?hash={rawurlencode($csrfToken)}"
|
||||
class="post-like-button"
|
||||
data-liked="{(int) $liked}"
|
||||
data-likes="{$post->getLikesCount()}">
|
||||
<div class="heart" id="{if $liked}liked{/if}"></div>
|
||||
<span class="likeCnt">{if $post->getLikesCount() > 0}{$post->getLikesCount()}{/if}</span>
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div n:if="isset($thisUser) &&! ($compact ?? false)" class="post-menu-s">
|
||||
<!-- kosfurler -->
|
||||
|
|
|
@ -265,6 +265,10 @@ routes:
|
|||
handler: "About->sandbox"
|
||||
- url: "/internal/wall{num}"
|
||||
handler: "Wall->wallEmbedded"
|
||||
- url: "/robots.txt"
|
||||
handler: "About->robotsTxt"
|
||||
- url: "/humans.txt"
|
||||
handler: "About->humansTxt"
|
||||
- url: "/{?shortCode}"
|
||||
handler: "UnknownTextRouteStrategy->delegate"
|
||||
placeholders:
|
||||
|
|
|
@ -334,6 +334,20 @@ a {
|
|||
width: 150px;
|
||||
}
|
||||
|
||||
.profile_link.disable > a, .profile_link.disable {
|
||||
cursor: not-allowed;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.profile_link.loading > a::after, .profile_link.loading::after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
background-image: url('/assets/packages/static/openvk/img/loading_mini.gif');
|
||||
width: 30px;
|
||||
height: 7px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.page_footer {
|
||||
margin-left: 95px;
|
||||
padding-top: 5px;
|
||||
|
@ -426,7 +440,15 @@ table {
|
|||
}
|
||||
|
||||
.button:hover {
|
||||
color: #e8e8e8;
|
||||
color: #e8e8e8;
|
||||
}
|
||||
|
||||
.button-loading {
|
||||
display: inline-block;
|
||||
background-image: url('/assets/packages/static/openvk/img/loading_mini.gif');
|
||||
width: 30px;
|
||||
height: 7px;
|
||||
margin-left: -3px;
|
||||
}
|
||||
|
||||
input[class=button] {
|
||||
|
@ -867,7 +889,6 @@ table.User {
|
|||
display: flex;
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
width: 611px;
|
||||
margin-left: 1px;
|
||||
border-bottom: 1px solid #d6d6d6;
|
||||
}
|
||||
|
@ -901,14 +922,13 @@ table.User {
|
|||
}
|
||||
|
||||
.crp-entry--message.unread {
|
||||
background-color: #dcdcdc;
|
||||
background-color: #ededed;
|
||||
padding: 5px;
|
||||
width: 346px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.messenger-app--messages---message.unread {
|
||||
background-color: #dcdcdc;
|
||||
background-color: #ededed;
|
||||
padding: 5px;
|
||||
margin: -5px;
|
||||
padding-bottom: 1.2rem;
|
||||
|
@ -923,8 +943,6 @@ table.User {
|
|||
}
|
||||
|
||||
.messenger-app--messages---message.unread:last-of-type {
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
padding-bottom: 5px;
|
||||
margin-bottom: 1.2rem;
|
||||
}
|
||||
|
@ -1754,3 +1772,16 @@ body.scrolled .toTop:hover {
|
|||
margin: -20px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.hover-box {
|
||||
background-color: white;
|
||||
padding: 10px;
|
||||
margin: 5px;
|
||||
border: 1px solid #C0CAD5;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.hover-box:hover {
|
||||
background-color: #C0CAD5;
|
||||
}
|
||||
|
|
BIN
Web/static/img/loading_mini.gif
Executable file
BIN
Web/static/img/loading_mini.gif
Executable file
Binary file not shown.
After Width: | Height: | Size: 246 B |
|
@ -17,10 +17,10 @@ function tr(string, ...args) {
|
|||
}
|
||||
|
||||
let newOutput = window.lang[numberedString];
|
||||
if(newOutput === null)
|
||||
if(newOutput == null)
|
||||
newOutput = window.lang[string + "_other"];
|
||||
|
||||
if(newOutput === null)
|
||||
if(newOutput == null)
|
||||
newOutput = output;
|
||||
|
||||
output = newOutput;
|
||||
|
|
|
@ -38,6 +38,22 @@ function hidePanel(panel, count = 0)
|
|||
|
||||
}
|
||||
|
||||
function parseAjaxResponse(responseString) {
|
||||
try {
|
||||
const response = JSON.parse(responseString);
|
||||
if(response.flash)
|
||||
NewNotification(response.flash.title, response.flash.message || "", null);
|
||||
|
||||
return response.success || false;
|
||||
} catch(error) {
|
||||
if(responseString === "Хакеры? Интересно...") {
|
||||
location.reload();
|
||||
return false;
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() { //BEGIN
|
||||
|
||||
|
@ -94,9 +110,21 @@ document.addEventListener("DOMContentLoaded", function() { //BEGIN
|
|||
let groupUrl = u(this).attr("data-group-url");
|
||||
let list = u('#_groupListPinnedGroups');
|
||||
|
||||
thisButton.nodes[0].classList.add('loading');
|
||||
thisButton.nodes[0].classList.add('disable');
|
||||
|
||||
let req = await ky(link);
|
||||
if(req.ok == false) {
|
||||
NewNotification(tr('error'), tr('error_1'), null);
|
||||
thisButton.nodes[0].classList.remove('loading');
|
||||
thisButton.nodes[0].classList.remove('disable');
|
||||
return;
|
||||
}
|
||||
|
||||
if(!parseAjaxResponse(await req.text())) {
|
||||
thisButton.nodes[0].classList.remove('loading');
|
||||
thisButton.nodes[0].classList.remove('disable');
|
||||
return;
|
||||
}
|
||||
|
||||
// Adding a divider if not already there
|
||||
|
@ -123,6 +151,9 @@ document.addEventListener("DOMContentLoaded", function() { //BEGIN
|
|||
list.nodes[0].children[0].remove();
|
||||
}
|
||||
|
||||
thisButton.nodes[0].classList.remove('loading');
|
||||
thisButton.nodes[0].classList.remove('disable');
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
|
@ -139,7 +170,7 @@ function repostPost(id, hash) {
|
|||
xhr.open("POST", "/wall"+id+"/repost?hash="+hash, true);
|
||||
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
xhr.onload = (function() {
|
||||
if(xhr.responseText.indexOf("wall_owner") === -1)
|
||||
if(xhr.responseText.indexOf("wall_owner") === -1)
|
||||
MessageBox(tr('error'), tr('error_repost_fail'), tr('ok'), [Function.noop]);
|
||||
else {
|
||||
let jsonR = JSON.parse(xhr.responseText);
|
||||
|
@ -217,3 +248,44 @@ function showCoinsTransferDialog(coinsCount, hash) {
|
|||
]);
|
||||
}
|
||||
|
||||
function chunkSubstr(string, size) {
|
||||
const numChunks = Math.ceil(string.length / size);
|
||||
const chunks = new Array(numChunks);
|
||||
|
||||
for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
|
||||
chunks[i] = string.substr(o, size);
|
||||
}
|
||||
|
||||
return chunks;
|
||||
}
|
||||
|
||||
function autoTab(original, next, previous) {
|
||||
if(original.getAttribute && original.value.length == original.getAttribute("maxlength") && next !== undefined)
|
||||
next.focus();
|
||||
else if(original.value.length == 0 && previous !== undefined)
|
||||
previous.focus();
|
||||
}
|
||||
|
||||
function showSupportFastAnswerDialog(answers) {
|
||||
let html = "";
|
||||
for(const [index, answer] of Object.entries(answers)) {
|
||||
html += `
|
||||
<div class="hover-box" onclick="supportFastAnswerDialogOnClick(fastAnswers[${index}])">
|
||||
${answer.replace(/\n/g, "<br />")}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
MessageBox(tr("fast_answers"), html, [tr("close")], [
|
||||
Function.noop
|
||||
]);
|
||||
}
|
||||
|
||||
function supportFastAnswerDialogOnClick(answer) {
|
||||
u("body").removeClass("dimmed");
|
||||
u(".ovk-diag-cont").remove();
|
||||
|
||||
const answerInput = document.querySelector("#answer_text");
|
||||
answerInput.value = answer;
|
||||
answerInput.focus();
|
||||
}
|
||||
|
|
|
@ -232,6 +232,14 @@ return (function() {
|
|||
else
|
||||
$ver = "Build 15";
|
||||
|
||||
// Unix time constants
|
||||
define('MINUTE', 60);
|
||||
define('HOUR', 60 * MINUTE);
|
||||
define('DAY', 24 * HOUR);
|
||||
define('WEEK', 7 * DAY);
|
||||
define('MONTH', 30 * DAY);
|
||||
define('YEAR', 365 * DAY);
|
||||
|
||||
define("nullptr", NULL);
|
||||
define("OPENVK_DEFAULT_INSTANCE_NAME", "OpenVK", false);
|
||||
define("OPENVK_VERSION", "Altair Preview ($ver)", false);
|
||||
|
|
|
@ -1 +1 @@
|
|||
ALTER TABLE `profiles` CHANGE `coins` `coins` REAL(20) UNSIGNED NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `profiles` CHANGE `coins` `coins` REAL UNSIGNED NOT NULL DEFAULT '0';
|
||||
|
|
|
@ -384,6 +384,7 @@
|
|||
"privacy_setting_see_friends" = "Who can see my friends";
|
||||
"privacy_setting_add_to_friends" = "Who can add me to friends";
|
||||
"privacy_setting_write_wall" = "Who can publish post on my wall";
|
||||
"privacy_setting_write_messages" = "Who can write messages to me";
|
||||
"privacy_value_anybody" = "Anybody";
|
||||
"privacy_value_anybody_dative" = "Anybody";
|
||||
"privacy_value_users" = "OpenVK users";
|
||||
|
@ -610,6 +611,8 @@
|
|||
"support_rated_bad" = "You left a negative feedback about the answer.";
|
||||
"wrong_parameters" = "Invalid request parameters.";
|
||||
|
||||
"fast_answers" = "Fast answers";
|
||||
|
||||
"comment" = "Comment";
|
||||
"sender" = "Sender";
|
||||
|
||||
|
@ -743,6 +746,7 @@
|
|||
|
||||
"login_as" = "Login as $1";
|
||||
"manage_user_action" = "Manage user";
|
||||
"manage_group_action" = "Manage group";
|
||||
"ban_user_action" = "Ban user";
|
||||
"warn_user_action" = "Warn user";
|
||||
|
||||
|
@ -764,7 +768,11 @@
|
|||
"cancel" = "Cancel";
|
||||
"edit_action" = "Change";
|
||||
"transfer" = "Transfer";
|
||||
"close" = "Close";
|
||||
|
||||
"warning" = "Warning";
|
||||
"question_confirm" = "This action can't be undone. Do you really wanna do it?";
|
||||
|
||||
/* User alerts */
|
||||
|
||||
"user_alert_scam" = "This account has been reported a lot for scam. Please be careful, especially if he asked for money.";
|
||||
|
|
|
@ -404,6 +404,7 @@
|
|||
"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";
|
||||
|
@ -639,6 +640,8 @@
|
|||
"support_rated_bad" = "Вы оставили негативный отзыв об ответе.";
|
||||
"wrong_parameters" = "Неверные параметры запроса.";
|
||||
|
||||
"fast_answers" = "Быстрые ответы";
|
||||
|
||||
"comment" = "Комментарий";
|
||||
"sender" = "Отправитель";
|
||||
|
||||
|
@ -778,6 +781,7 @@
|
|||
|
||||
"login_as" = "Войти как $1";
|
||||
"manage_user_action" = "Управление пользователем";
|
||||
"manage_group_action" = "Управление группой";
|
||||
"ban_user_action" = "Заблокировать пользователя";
|
||||
"warn_user_action" = "Предупредить пользователя";
|
||||
|
||||
|
@ -799,6 +803,11 @@
|
|||
"cancel" = "Отмена";
|
||||
"edit_action" = "Изменить";
|
||||
"transfer" = "Передать";
|
||||
"close" = "Закрыть";
|
||||
|
||||
"warning" = "Внимание";
|
||||
"question_confirm" = "Это действие нельзя отменить. Вы действительно уверены в том что хотите сделать?";
|
||||
|
||||
/* User alerts */
|
||||
|
||||
"user_alert_scam" = "На этот аккаунт много жаловались в связи с мошенничеством. Пожалуйста, будьте осторожны, особенно если у вас попросят денег.";
|
||||
|
|
|
@ -31,6 +31,10 @@ openvk:
|
|||
support:
|
||||
supportName: "Moderator"
|
||||
adminAccount: 1 # Change this ok
|
||||
fastAnswers:
|
||||
- "This is a list of quick answers to common questions for support. Post your responses here and agents can send it quickly with just 3 clicks"
|
||||
- "There can be as many answers as you want, but it is best to have a maximum of 10.\n\nYou can also remove all answers from the list to disable this feature"
|
||||
- "Good luck filling! If you are a regular support agent, inform the administrator that he forgot to fill the config"
|
||||
messages:
|
||||
strict: false
|
||||
wall:
|
||||
|
|
Loading…
Reference in a new issue