mirror of
https://github.com/openvk/openvk
synced 2024-11-14 02:59:12 +03:00
Users: Add ability to transfer votes to another user
This commit is contained in:
parent
cb8c2f683b
commit
3b54c4b878
10 changed files with 184 additions and 0 deletions
|
@ -0,0 +1,13 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Entities\Notifications;
|
||||||
|
use openvk\Web\Models\Entities\{User, Gift};
|
||||||
|
|
||||||
|
final class CoinsTransferNotification extends Notification
|
||||||
|
{
|
||||||
|
protected $actionCode = 9602;
|
||||||
|
|
||||||
|
function __construct(User $receiver, User $sender, int $value, string $message)
|
||||||
|
{
|
||||||
|
parent::__construct($receiver, $receiver, $sender, time(), $value . " " . $message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,6 +52,23 @@ class Users
|
||||||
"online" => sizeof((clone $this->users)->where("online >= ?", time() - 900)),
|
"online" => sizeof((clone $this->users)->where("online >= ?", time() - 900)),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getByAddress(string $address): ?User
|
||||||
|
{
|
||||||
|
if(substr_compare($address, "/", -1) === 0)
|
||||||
|
$address = substr($address, 0, iconv_strlen($address) - 1);
|
||||||
|
|
||||||
|
$serverUrl = ovk_scheme(true) . $_SERVER["SERVER_NAME"];
|
||||||
|
if(strpos($address, $serverUrl . "/") === 0)
|
||||||
|
$address = substr($address, iconv_strlen($serverUrl) + 1);
|
||||||
|
|
||||||
|
if(strpos($address, "id") === 0) {
|
||||||
|
$user = $this->get((int) substr($address, 2));
|
||||||
|
if($user) return $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getByShortUrl($address);
|
||||||
|
}
|
||||||
|
|
||||||
use \Nette\SmartObject;
|
use \Nette\SmartObject;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ use openvk\Web\Models\Repositories\Videos;
|
||||||
use openvk\Web\Models\Repositories\Notes;
|
use openvk\Web\Models\Repositories\Notes;
|
||||||
use openvk\Web\Models\Repositories\Vouchers;
|
use openvk\Web\Models\Repositories\Vouchers;
|
||||||
use openvk\Web\Util\Validator;
|
use openvk\Web\Util\Validator;
|
||||||
|
use openvk\Web\Models\Entities\Notifications\CoinsTransferNotification;
|
||||||
use Chandler\Security\Authenticator;
|
use Chandler\Security\Authenticator;
|
||||||
use lfkeitel\phptotp\{Base32, Totp};
|
use lfkeitel\phptotp\{Base32, Totp};
|
||||||
use chillerlan\QRCode\{QRCode, QROptions};
|
use chillerlan\QRCode\{QRCode, QROptions};
|
||||||
|
@ -465,4 +466,42 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
$this->user->identity->save();
|
$this->user->identity->save();
|
||||||
$this->flashFail("succ", tr("information_-1"), tr("two_factor_authentication_disabled_message"));
|
$this->flashFail("succ", tr("information_-1"), tr("two_factor_authentication_disabled_message"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderCoinsTransfer(): void
|
||||||
|
{
|
||||||
|
$this->assertUserLoggedIn();
|
||||||
|
$this->willExecuteWriteAction();
|
||||||
|
|
||||||
|
$receiverAddress = $this->postParam("receiver");
|
||||||
|
$value = (int) $this->postParam("value");
|
||||||
|
$message = $this->postParam("message");
|
||||||
|
|
||||||
|
if(!$receiverAddress || !$value)
|
||||||
|
$this->flashFail("err", tr("failed_to_tranfer_points"), tr("not_all_information_has_been_entered"));
|
||||||
|
|
||||||
|
if($value < 0)
|
||||||
|
$this->flashFail("err", tr("failed_to_tranfer_points"), tr("negative_transfer_value"));
|
||||||
|
|
||||||
|
if(iconv_strlen($message) > 255)
|
||||||
|
$this->flashFail("err", tr("failed_to_tranfer_points"), tr("message_is_too_long"));
|
||||||
|
|
||||||
|
$receiver = $this->users->getByAddress($receiverAddress);
|
||||||
|
if(!$receiver)
|
||||||
|
$this->flashFail("err", tr("failed_to_tranfer_points"), tr("receiver_not_found"));
|
||||||
|
|
||||||
|
if($this->user->identity->getCoins() < $value)
|
||||||
|
$this->flashFail("err", tr("failed_to_tranfer_points"), tr("you_dont_have_enough_points"));
|
||||||
|
|
||||||
|
if($this->user->id !== $receiver->getId()) {
|
||||||
|
$this->user->identity->setCoins($this->user->identity->getCoins() - $value);
|
||||||
|
$this->user->identity->save();
|
||||||
|
|
||||||
|
$receiver->setCoins($receiver->getCoins() + $value);
|
||||||
|
$receiver->save();
|
||||||
|
|
||||||
|
(new CoinsTransferNotification($receiver, $this->user->identity, $value, $message))->emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->flashFail("succ", tr("information_-1"), tr("points_transfer_successful", tr("points_amount", $value), $receiver->getURL(), htmlentities($receiver->getCanonicalName())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -332,6 +332,7 @@
|
||||||
|
|
||||||
<div style="width: 75%; display: inline-block;">
|
<div style="width: 75%; display: inline-block;">
|
||||||
{presenter "openvk!Support->knowledgeBaseArticle", "points"}
|
{presenter "openvk!Support->knowledgeBaseArticle", "points"}
|
||||||
|
<center>{tr("also_you_can_transfer_points", $thisUser->getCoins(), rawurlencode($csrfToken))|noescape}</center>
|
||||||
</div>
|
</div>
|
||||||
<div style="width: 22%; float: right;">
|
<div style="width: 22%; float: right;">
|
||||||
<p style="margin: 0; font-size: medium; text-align: center;">
|
<p style="margin: 0; font-size: medium; text-align: center;">
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
{var sender = $notification->getModel(1)}
|
||||||
|
{var value = (int) explode(" ", $notification->getData(), 2)[0]}
|
||||||
|
{var message = explode(" ", $notification->getData(), 2)[1]}
|
||||||
|
|
||||||
|
<a href="{$sender->getURL()}"><b>{$sender->getCanonicalName()}</b></a> {_transferred_to_you} {tr("points_amount", $value)}.
|
||||||
|
{if !empty($message)}
|
||||||
|
{_message}: "{$message}".
|
||||||
|
{/if}
|
|
@ -59,6 +59,8 @@ routes:
|
||||||
handler: "User->twoFactorAuthSettings"
|
handler: "User->twoFactorAuthSettings"
|
||||||
- url: "/settings/2fa/disable"
|
- url: "/settings/2fa/disable"
|
||||||
handler: "User->disableTwoFactorAuth"
|
handler: "User->disableTwoFactorAuth"
|
||||||
|
- url: "/coins_transfer"
|
||||||
|
handler: "User->coinsTransfer"
|
||||||
- url: "/id{num}"
|
- url: "/id{num}"
|
||||||
handler: "User->view"
|
handler: "User->view"
|
||||||
- url: "/friends{num}"
|
- url: "/friends{num}"
|
||||||
|
|
|
@ -1687,3 +1687,9 @@ body.scrolled .toTop:hover {
|
||||||
border-bottom: #e6e6e6 solid 1px;
|
border-bottom: #e6e6e6 solid 1px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.messagebox-content-header {
|
||||||
|
background: #F7F7F7;
|
||||||
|
margin: -20px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
|
@ -171,3 +171,49 @@ function setClubAdminComment(clubId, adminId, hash) {
|
||||||
Function.noop
|
Function.noop
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showCoinsTransferDialog(coinsCount, hash) {
|
||||||
|
MessageBox(tr("transfer_poins"), `
|
||||||
|
<div class="messagebox-content-header">
|
||||||
|
${tr("points_transfer_dialog_header_1")}
|
||||||
|
${tr("points_transfer_dialog_header_2")} <b>${tr("points_amount", coinsCount)}</b>
|
||||||
|
</div>
|
||||||
|
<form action="/coins_transfer" method="post" id="coins_transfer_form" style="margin-top: 30px">
|
||||||
|
<table cellspacing="7" cellpadding="0" border="0" align="center">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td width="120" valign="top">
|
||||||
|
<span class="nobold">${tr("receiver_address")}:</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="receiver" style="width: 100%;" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="120" valign="top">
|
||||||
|
<span class="nobold">${tr("coins_count")}:</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="value" style="width: 100%;" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="120" valign="top">
|
||||||
|
<span class="nobold">${tr("message")}:</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<textarea name="message" style="width: 100%;"></textarea>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<input type="hidden" name="hash" value="${hash}" />
|
||||||
|
</form>
|
||||||
|
`, [tr("transfer_poins_button"), tr("cancel")], [
|
||||||
|
() => {
|
||||||
|
document.querySelector("#coins_transfer_form").submit();
|
||||||
|
},
|
||||||
|
Function.noop
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -524,6 +524,31 @@
|
||||||
"usages_total" = "Number of uses";
|
"usages_total" = "Number of uses";
|
||||||
"usages_left" = "Uses left";
|
"usages_left" = "Uses left";
|
||||||
|
|
||||||
|
"points_transfer_dialog_header_1" = "You can send as a gift or transfer part of the votes to another person.";
|
||||||
|
"points_transfer_dialog_header_2" = "Your current balance:";
|
||||||
|
|
||||||
|
"points_amount_one" = "1 vote";
|
||||||
|
"points_amount_other" = "$1 votes";
|
||||||
|
|
||||||
|
"transfer_poins" = "Transfer votes";
|
||||||
|
"transfer_poins_button" = "Transfer votes";
|
||||||
|
"also_you_can_transfer_points" = "You can also <a href=\"javascript:showCoinsTransferDialog($1, '$2')\">transfer votes</a> to another person.";
|
||||||
|
|
||||||
|
"transferred_to_you" = "transferred to you";
|
||||||
|
|
||||||
|
"receiver_address" = "Receiver address";
|
||||||
|
"coins_count" = "Number of votes";
|
||||||
|
"message" = "Message";
|
||||||
|
|
||||||
|
"failed_to_tranfer_points" = "Failed to transfer votes";
|
||||||
|
|
||||||
|
"points_transfer_successful" = "You have successfully transferred <b>$1</b> to <b><a href=\"$2\">$3</a></b>.";
|
||||||
|
"not_all_information_has_been_entered" = "Not all information has been entered.";
|
||||||
|
"negative_transfer_value" = "We cannot steal votes from another person, sorry.";
|
||||||
|
"message_is_too_long" = "The message is too long.";
|
||||||
|
"receiver_not_found" = "The receiver was not found.";
|
||||||
|
"you_dont_have_enough_points" = "You don't have enough votes.";
|
||||||
|
|
||||||
/* Gifts */
|
/* Gifts */
|
||||||
|
|
||||||
"gift" = "Gift";
|
"gift" = "Gift";
|
||||||
|
|
|
@ -546,6 +546,33 @@
|
||||||
"usages_total" = "Количество использований";
|
"usages_total" = "Количество использований";
|
||||||
"usages_left" = "Осталось использований";
|
"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 */
|
/* Gifts */
|
||||||
|
|
||||||
"gift" = "Подарок";
|
"gift" = "Подарок";
|
||||||
|
|
Loading…
Reference in a new issue