Merge branch 'master' of github.com:openvk/openvk

This commit is contained in:
veselcraft 2022-02-07 19:40:20 +03:00
commit 8c44721a1e
No known key found for this signature in database
GPG key ID: AED66BC1AC628A4E
14 changed files with 274 additions and 96 deletions

View file

@ -40,7 +40,7 @@ class Club extends RowModel
function getAvatarUrl(): string
{
$serverUrl = ovk_scheme(true) . $_SERVER["SERVER_NAME"];
$serverUrl = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
$avPhoto = $this->getAvatarPhoto();
return is_null($avPhoto) ? "$serverUrl/assets/packages/static/openvk/img/camera_200.png" : $avPhoto->getURL();
@ -64,16 +64,6 @@ class Club extends RowModel
else
return "/club" . $this->getId();
}
/*
function getAvatarUrl(): string
{
$avAlbum = (new Albums)->getUserAvatarAlbum($this);
$avCount = $avAlbum->getPhotosCount();
$avPhotos = $avAlbum->getPhotos($avCount, 1);
$avPhoto = iterator_to_array($avPhotos)[0] ?? NULL;
return is_null($avPhoto) ? "/assets/packages/static/openvk/img/camera_200.png" : $avPhoto->getURL();
} */
function getName(): string
{

View file

@ -5,6 +5,7 @@ use openvk\Web\Util\DateTime;
use openvk\Web\Models\RowModel;
use openvk\Web\Models\Entities\{Photo, Message, Correspondence, Gift};
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Gifts, Notifications};
use openvk\Web\Models\Exceptions\InvalidUserNameException;
use Nette\Database\Table\ActiveRow;
use Chandler\Database\DatabaseConnection;
use Chandler\Security\User as ChandlerUser;
@ -103,7 +104,7 @@ class User extends RowModel
function getAvatarUrl(): string
{
$serverUrl = ovk_scheme(true) . $_SERVER["SERVER_NAME"];
$serverUrl = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
if($this->getRecord()->deleted)
return "$serverUrl/assets/packages/static/openvk/img/camera_200.png";
@ -739,6 +740,24 @@ class User extends RowModel
return true;
}
function setFirst_Name(string $firstName): void
{
$firstName = mb_convert_case($firstName, MB_CASE_TITLE);
if(!preg_match('%^\p{Lu}\p{Mn}?(?:\p{L&}\p{Mn}?){1,16}$%u', $firstName))
throw new InvalidUserNameException;
$this->stateChanges("first_name", $firstName);
}
function setLast_Name(string $lastName): void
{
$lastName = mb_convert_case($lastName, MB_CASE_TITLE);
if(!preg_match('%^\p{Lu}\p{Mn}?(\p{L&}\p{Mn}?){1,16}(\-\g<1>+)?$%u', $lastName))
throw new InvalidUserNameException;
$this->stateChanges("last_name", $lastName);
}
function setNsfwTolerance(int $tolerance): void
{
$this->stateChanges("nsfw_tolerance", $tolerance);

View file

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Exceptions;
final class InvalidUserNameException extends \UnexpectedValueException
{
protected $message = "Invalid real name supplied";
}

View file

@ -5,7 +5,7 @@ final class YouTubeVideoDriver extends VideoDriver
{
function getThumbnailURL(): string
{
return "https://img.youtube.com/vi/$this->id/mq3.jpg";
return "https://img.youtube.com/vi/$this->id/mqdefault.jpg";
}
function getURL(): string

View file

@ -9,6 +9,7 @@ use openvk\Web\Models\Repositories\Albums;
use openvk\Web\Models\Repositories\Videos;
use openvk\Web\Models\Repositories\Notes;
use openvk\Web\Models\Repositories\Vouchers;
use openvk\Web\Models\Exceptions\InvalidUserNameException;
use openvk\Web\Util\Validator;
use openvk\Web\Models\Entities\Notifications\CoinsTransferNotification;
use Chandler\Security\Authenticator;
@ -137,8 +138,13 @@ final class UserPresenter extends OpenVKPresenter
$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"));
$user->setLast_Name(empty($this->postParam("last_name")) ? "" : $this->postParam("last_name"));
try {
$user->setFirst_Name(empty($this->postParam("first_name")) ? $user->getFirstName() : $this->postParam("first_name"));
$user->setLast_Name(empty($this->postParam("last_name")) ? "" : $this->postParam("last_name"));
} catch(InvalidUserNameException $ex) {
$this->flashFail("err", tr("error"), tr("invalid_real_name"));
}
$user->setPseudo(empty($this->postParam("pseudo")) ? NULL : $this->postParam("pseudo"));
$user->setStatus(empty($this->postParam("status")) ? NULL : $this->postParam("status"));
if (strtotime($this->postParam("birthday")) < time())

View file

@ -262,7 +262,7 @@
<a href="/privacy" class="link">{_footer_privacy}</a>
</div>
<p>OpenVK <a href="/about:openvk">{php echo OPENVK_VERSION}</a> | PHP: {phpversion()} | DB: {$dbVersion}</p>
<p n:ifcontent="ifcontent">
<p n:ifcontent>
{php echo OPENVK_ROOT_CONF["openvk"]["appearance"]["motd"]}
</p>
</div>

View file

@ -9,58 +9,62 @@
{ifset size}
{include size, x => $dat}
{/ifset}
{ifset specpage}
{include specpage, x => $dat}
{else}
<div class="container_gray">
{var data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
<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>
<tbody>
<tr>
<td valign="top">
<a href="{include link, x => $dat}">
{include preview, x => $dat}
</a>
</td>
<td valign="top" style="width: 100%">
{ifset infoTable}
{include infoTable, x => $dat}
{else}
{if sizeof($data) > 0}
<div class="content" n:foreach="$data as $dat">
<table>
<tbody>
<tr>
<td valign="top">
<a href="{include link, x => $dat}">
<b>
{include name, x => $dat}
</b>
{include preview, x => $dat}
</a>
<br/>
{include description, x => $dat}
{/ifset}
</td>
<td n:ifset="actions" valign="top" class="action_links" style="width: 150px; text-transform: lowercase;">
{include actions, x => $dat}
</td>
</tr>
</tbody>
</table>
</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}
</td>
<td valign="top" style="width: 100%">
{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; text-transform: lowercase;">
{include actions, x => $dat}
</td>
</tr>
</tbody>
</table>
</div>
{include "components/paginator.xml", conf => (object) [
"page" => $page,
"count" => $count,
"amount" => sizeof($data),
"perPage" => $perPage ?? OPENVK_DEFAULT_PER_PAGE,
"atBottom" => true,
]}
{else}
{include "components/nothing.xml"}
{/ifset}
{/if}
</div>
{ifset customErrorMessage}
{include customErrorMessage}
{else}
{include "components/nothing.xml"}
{/ifset}
{/if}
</div>
{/ifset}
{ifset bottom}
{include bottom}
{/ifset}
</div>
{/block}
{/block}

View file

@ -5,12 +5,25 @@
{block title}{_notes}{/block}
{block header}
<a href="{$owner->getURL()}">{$owner->getCanonicalName()}</a>
»
{_notes}
<div n:if="isset($thisUser) && $thisUser->getId() == $owner->getId()" style="float:right;">
<a href="/notes/create">{_create_note}</a>
{if isset($thisUser) && $thisUser->getId() == $owner->getId()}
{_my_notes}
{else}
<a href="{$owner->getURL()}">
{$owner->getCanonicalName()}</a>
»
{_notes}
{/if}
{/block}
{block size}
<div style="padding-bottom: 0px; padding-top: 0;" class="summaryBar">
<div class="summary">
{tr("notes_list", $count)}
<span n:if="isset($thisUser) && $thisUser->getId() == $owner->getId()">
&nbsp;|&nbsp;
<a href="/notes/create">{_create_note}</a>
</span>
</div>
</div>
{/block}
@ -20,18 +33,66 @@
{* BEGIN ELEMENTS DESCRIPTION *}
{block link|strip|stripHtml}
/note{$x->getPrettyId()}
{/block}
{block specpage}
<div class="container_gray" style="background: white; border-top: none;">
{block preview}
<center><img src="/assets/packages/static/openvk/img/note_icon.png" alt="{_note}" style="margin-top: 17px;" /></center>
{/block}
{var data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
{if sizeof($data) > 0}
{block name}
{$x->getName()}
{/block}
<div n:foreach="$data as $dat">
<div class="profile_thumb">
<a href="{$owner->getURL()}">
<img src="{$owner->getAvatarUrl()}" style="width: 50px;">
</a>
</div>
<article class="note_body" id="userContent" style="width: 540px; display: inline-block; margin-bottom: 35px;">
<div class="note_header">
<div class="note_title">
<div class="note_title">
<a href="/note{$dat->getPrettyId()}">{$dat->getName()}</a>
</div>
</div>
<div class="byline">
<span><a href="{$owner->getURL()}">{$owner->getCanonicalName()}</a></span> {$dat->getPublicationTime()}
<span n:if="$dat->getEditTime() > $dat->getPublicationTime()">({_edited} {$dat->getEditTime()})</span>
</div>
</div>
<div style="margin-left: 6px;">
{$dat->getText(750)|noescape}
</div>
<div class="note_footer" style="margin: 10px 0 0;">
<div class="comments_count">
<a href="/note{$dat->getPrettyId()}">
{block description}
{$x->getPreview(250)}
{if sizeof($dat->getCommentsCount()) > 0}
{_comments} ({$dat->getCommentsCount()})
{else}
{_no_comments}
{/if}
</a>
<span n:if="isset($thisUser) && $thisUser->getId() === $dat->getOwner()->getId()">&nbsp;|&nbsp;
<a id="_noteDelete" href="/note{$dat->getOwner()->getId()}_{$dat->getId()}/delete">{_delete}</a>
&nbsp;|&nbsp;
<a href="/note{$dat->getOwner()->getId()}_{$dat->getVirtualId()}/edit">{_edit}</a>
</span>
</div>
</div>
</article>
</div>
{else}
{if isset($thisUser) && $thisUser->getId() == $owner->getId()}
<div style="padding: 10px 20px 20px;"><h4 style="border: none;padding-bottom: 5px;">{_welcome}</h4>{_notes_start_screen}</div>
{else}
{ifset customErrorMessage}
{include ../customErrorMessage}
{else}
{include ../components/nothing.xml}
{/ifset}
{/if}
{/if}
</div>
{/block}

View file

@ -51,6 +51,8 @@
<img src="{$x->getAvatarUrl()}" width="75" alt="Фотография группы" />
{/block}
{block name}{/block}
{block infoTable}
<table id="basicInfo" class="ugc-table group_info" cellspacing="0" cellpadding="0" border="0">
<tbody>
@ -72,19 +74,19 @@
{block actions}
{var clubPinned = $thisUser->isClubPinned($x)}
{if $x->canBeModifiedBy($thisUser ?? NULL) && ($clubPinned || $thisUser->getPinnedClubCount() <= 10)}
{if $x->canBeModifiedBy($thisUser ?? NULL)}
<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>
{if ($clubPinned || $thisUser->getPinnedClubCount() <= 10)}
<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>
{/if}
<form action="/setSub/club" method="post">
<input type="hidden" name="act" value="rem" />
<input type="hidden" name="id" value="{$x->getId()}" />

View file

@ -8,9 +8,17 @@
{block header}
<a href="{$user->getURL()}">{$user->getCanonicalName()}</a>
» {_"videos"}
<div n:if="isset($thisUser) && $thisUser->getId() == $user->getId()" style="float: right;">
<a href="/videos/upload">{_"upload_video"}</a>
{/block}
{block size}
<div style="padding-bottom: 0px;border-bottom: 0; padding-top: 0;" class="summaryBar">
<div class="summary">
{tr("videos", $count)}
<span n:if="isset($thisUser) && $thisUser->getId() == $user->getId()">
&nbsp;|&nbsp;
<a href="/videos/upload">{_upload_video}</a>
</span>
</div>
</div>
{/block}

View file

@ -1866,6 +1866,17 @@ body.scrolled .toTop:hover {
padding-right: 5px;
}
table td[width="120"] {
text-align: right;
}
.profile_thumb {
padding: 0px 10px 0px 0px;
width: 50px;
display: inline-block;
vertical-align: top;
}
.border-block {
box-shadow: inset 0px 0 0px 1px #b6bfca, inset 0px 0 0px 10px #d8dfe7;
width: 300px;
@ -1874,4 +1885,4 @@ body.scrolled .toTop:hover {
.center {
margin: 0 auto;
}
}

View file

@ -323,6 +323,7 @@
"notes_zero" = "No notes";
"notes_one" = "$1 note";
"notes_other" = "$1 notes";
"notes_start_screen" = "With notes, you can share your events with friends and see what's going on with them.";
/* Menus */
@ -750,6 +751,8 @@
"invalid_email_address" = "Invalid Email address";
"invalid_email_address_comment" = "The Email you entered is not correct.";
"invalid_real_name" = "Please, enter your real name. It'll be easier for your friends to find you like this.";
"invalid_birth_date" = "Invalid date of birth";
"invalid_birth_date_comment" = "The date of birth you entered is not correct.";

View file

@ -9,6 +9,8 @@
"home" = "Басты бет";
"welcome" = "Қош келдіңіз!";
"to_top" = "Жоғарыға";
/* Login */
"log_in" = "Логин";
@ -36,6 +38,13 @@
"password_reset_error" = "Құпиясөзді қалпына келтіру кезінде күтпеген қате орын алды.";
"password_reset_rate_limit_error" = "Кешіріңіз, бірақ осы әрекетті сонай жиі жасай алмайсыз.";
"email_sent" = "Хат сәтті жіберілді.";
"email_sent_desc" = "Сіз енгізген электрондық пошта бар болса оған нұсқаулар келеді.";
"email_error" = "Электрондық хатты жіберу кезінде күтпеген қате орын алды.";
"email_rate_limit_error" = "Бұл әрекетті жиі жасай алмайсыз.";
"email_verify_success" = "Электрондық поштаңыз расталды. Осы әлеуметтік желіде жақсы уақыт өткізуді тілейміз!";
"registration_disabled_info" = "Жүйе әкімшісі тіркеуді өшірді. Мүмкіндігінше, егер досыңыз сайтта тіркелген болса одан шақыру сілтемесін сұраңыз.";
"registration_closed" = "Тіркелу жабық";
"invites_you_to" = "<strong>$1</strong> сізді $2 желіне шақырады.";
@ -216,6 +225,7 @@
"subscriptions" = "Жазылымдар";
"join_community" = "Топқа кіру";
"leave_community" = "Топтан шығу";
"check_community" = "Топты қарау";
"min_6_community" = "Топтың аты тым болмаса 6 әріптен көп болу керек";
"participants" = "Қатысушылар";
"groups" = "Топтар";
@ -232,6 +242,8 @@
"all_followers" = "Барлық жазылмандар";
"only_administrators" = "Тек әкімшілер";
"website" = "Сайт";
"managed" = "Басқаратын";
"size" = "Көлемі";
"administrators_one" = "$1 әкімші";
"administrators_other" = "$1 әкімші";
@ -245,6 +257,7 @@
"hidden_yes" = "Жасырылған: Ия";
"hidden_no" = "Жасырылған: Жоқ";
"group_allow_post_for_everyone" = "Бәріне жазба жазуға рұқсат ету";
"group_hide_from_global_feed" = "Жаһандық арнада жазбаларды көрсетпеу";
"statistics" = "Статистика";
"group_administrators_list" = "Әкімшілер тізімі";
"group_display_only_creator" = "Тек топты құрған кісіні көрсету";
@ -263,10 +276,20 @@
"groups_one" = "$1 топ";
"groups_other" = "$1 топ";
"groups_list_zero" = "Сіз ешқандай топқа қатыспайсыз.";
"groups_list_one" = "Сіз бір топқа қатысасыз";
"groups_list_other" = "Сіз $1 топтардың қатысушысысыз";
"meetings_zero" = "Кездесулер жоқ";
"meetings_one" = "$1 кездесу";
"meetings_other" = "$1 кездесу";
"open_new_group" = "Жаңа топ ашу";
"open_group_desc" = "Өзіңізге сай топ таба алмай жүрсіз бе? Өзіңіз ашып алыңыз!";
"search_group" = "Топ іздеу";
"search_by_groups" = "Топтардан іздеу";
"search_group_desc" = "Мұнда сіз бар топтарға шолу жасай аласыз және қажеттіліктеріңізге сай топты таңдай аласыз...";
/* Albums */
"create" = "Жасау";
@ -294,10 +317,13 @@
"name_note" = "Тақырыбы";
"text_note" = "Мазмұны";
"create_note" = "Жолжазба жазу";
"edit_note" = "Жолжазбаны өндеу";
"actions" = "Әрекеттер";
"feed" = "Жаңалықтар";
"publish_post" = "Жазба қосу";
"edited" = "Өнделген";
"notes_zero" = "Жолжазбалар жоқ";
"notes_one" = "$1 жолжазба";
"notes_other" = "$1 жолжазба";
@ -337,6 +363,7 @@
"left_menu_donate" = "Қайырымдылық жасау";
"footer_about_instance" = "инстанция туралы";
"footer_blog" = "блог";
"footer_help" = "көмек";
"footer_developers" = "әзірлеушілерге";
@ -367,6 +394,8 @@
"cut" = "Кесілген";
"round_avatars" = "Дөңгелектелген";
"apply_style_for_this_device" = "Стильді тек осы девайс үшін қосу";
"search_for_groups" = "Топтар іздеу";
"search_for_people" = "Кісілер іздеу";
"search_button" = "Іздеу";
@ -391,6 +420,7 @@
"ui_settings_rating_hide" = "Жасыру";
"additional_links" = "Қосымша сілтемелер";
"ad_poster" = "Жарнама постері";
"two_factor_authentication" = "Екі факторлы аутентификация";
"two_factor_authentication_disabled" = "Бұзылудан сенімді қорғаныс қызметін қамтамасыз етеді: парақшаға кіру үшін 2FA қосымшасында алынған кодты енгізу керек.";
@ -637,6 +667,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>, тіркелуіңіз аяқталуға жақын. Бірнеше минуттан кейін электрондық поштаңызға растау сілтемесі бар хат келуі керек.";
"ec_2" = "Егер қандай да бір себептермен хат келмесе, спам қалтасын тексеріңіз. Хатты ол жерден таппасаңыз, оны қайта жіберуге болады.";
"ec_resend" = "Қайта жіберу";
/* Discussions */
"discussions" = "Талқылаулар";
@ -718,7 +756,7 @@
"invalid_telegram_name" = "Telegram парақшаның аты қате";
"invalid_telegram_name_comment" = "Сіз енгізген Telegram-дағы парақшаның аты дұрыс емес.";
"token_manipulation_error" = "Токенді өңдеу қатесі";
"token_manipulation_error" = "Токенді өндеу қатесі";
"token_manipulation_error_comment" = "Токен жарамсыз немесе мерзімі өтіп кеткен";
"profile_changed" = "Парақша өзгерілді";
@ -758,6 +796,26 @@
"about_openvk" = "OpenVK туралы";
"about_this_instance" = "Инстанция туралы";
"rules" = "Ережелер";
"most_popular_groups" = "Ең танымал топтар";
"on_this_instance_are" = "Осы инстанцияда:";
"about_users_one" = "<b>1</b> қолданушы";
"about_users_other" = "<b>$1</b> қолданушы";
"about_online_users_one" = "<b>1</b> желідегі пайдаланушы";
"about_online_users_other" = "<b>$1</b> желідегі пайдаланушы";
"about_active_users_one" = "<b>1</b> белсенді пайдаланушы";
"about_active_users_other" = "<b>$1</b> белсенді пайдаланушы";
"about_groups_one" = "<b>1</b> топ";
"about_groups_other" = "<b>$1</b> топ";
"about_wall_posts_one" = "<b>1</b> жазба";
"about_wall_posts_other" = "<b>$1</b> жазба";
/* Dialogs */
"ok" = "ОК";

View file

@ -332,9 +332,10 @@
"note" = "Заметка";
"name_note" = "Название";
"text_note" = "Содержание";
"create_note" = "Создать заметку";
"create_note" = "Добавить запись";
"edit_note" = "Редактировать заметку";
"actions" = "Действия";
"notes_start_screen" = "С помощью заметок Вы можете делиться событиями из жизни с друзьями, а так же быть в курсе того, что происходит у них.";
"edited" = "Отредактировано";
@ -344,6 +345,12 @@
"notes_many" = "$1 заметок";
"notes_other" = "$1 заметок";
"notes_list_zero" = "Не найдено ни одной заметки";
"notes_list_one" = "Найдена одна заметка";
"notes_list_few" = "Найдено $1 заметки";
"notes_list_many" = "Найдено $1 заметок";
"notes_list_other" = "Найдено $1 заметок";
/* Menus */
"edit_button" = "ред.";
@ -510,7 +517,7 @@
"info_uploaded_by" = "Загрузил";
"info_upload_date" = "Дата загрузки";
"videos_zero" = "Ни одной видеозаписи";
"videos_zero" = "Нет видео";
"videos_one" = "Одна видеозапись";
"videos_few" = "$1 видеозаписи";
"videos_many" = "$1 видеозаписей";
@ -785,6 +792,8 @@
"invalid_email_address" = "Неверный Email адрес";
"invalid_email_address_comment" = "Email, который вы ввели, не является корректным.";
"invalid_real_name" = "Пожалуйста, используйте реальные имена. Так вашим тульпам будет легче найти вас.";
"invalid_telegram_name" = "Неверное имя Telegram аккаунта";
"invalid_telegram_name_comment" = "Вы ввели неверное имя аккаунта Telegram.";