Add User::getMorphedName

This commit is contained in:
Celestora 2022-04-12 20:10:35 +03:00
parent 2c6fa71e20
commit f3f62a63ac
5 changed files with 193 additions and 101 deletions

View file

@ -38,6 +38,7 @@
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/console" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php80" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/service-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/wapmorgan/morphos" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

View file

@ -39,6 +39,7 @@
<path value="$PROJECT_DIR$/vendor/symfony/console" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php80" />
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
<path value="$PROJECT_DIR$/vendor/wapmorgan/morphos" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="7.4">

View file

@ -1,5 +1,6 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Entities;
use morphos\Gender;
use openvk\Web\Themes\{Themepack, Themepacks};
use openvk\Web\Util\DateTime;
use openvk\Web\Models\RowModel;
@ -9,6 +10,7 @@ use openvk\Web\Models\Exceptions\InvalidUserNameException;
use Nette\Database\Table\ActiveRow;
use Chandler\Database\DatabaseConnection;
use Chandler\Security\User as ChandlerUser;
use function morphos\Russian\inflectName;
class User extends RowModel
{
@ -166,50 +168,61 @@ class User extends RowModel
return $this->getFirstName() . $pseudo . $this->getLastName();
}
function getMorphedName(string $case = "genitive", bool $fullName = true): string
{
$name = $fullName ? ($this->getLastName() . " " . $this->getFirstName()) : $this->getFirstName();
if(!preg_match("%^[А-яё\-]+$%", $name))
return $name; # name is probably not russian
$inflected = inflectName($name, $case, $this->isFemale() ? Gender::FEMALE : Gender::MALE);
return $inflected ?: $name;
}
function getCanonicalName(): string
{
if($this->getRecord()->deleted)
if($this->getRecord()->deleted)
return "DELETED";
else
return $this->getFirstName() . ' ' . $this->getLastName();
else
return $this->getFirstName() . " " . $this->getLastName();
}
function getPhone(): ?string
{
return $this->getRecord()->phone;
}
function getEmail(): ?string
{
return $this->getRecord()->email;
}
function getOnline(): DateTime
{
return new DateTime($this->getRecord()->online);
}
function getDescription(): ?string
{
return $this->getRecord()->about;
}
function getStatus(): ?string
{
return $this->getRecord()->status;
}
function getShortCode(): ?string
{
return $this->getRecord()->shortcode;
}
function getAlert(): ?string
{
return $this->getRecord()->alert;
}
function getBanReason(): ?string
{
return $this->getRecord()->block_reason;
@ -219,105 +232,105 @@ class User extends RowModel
{
return $this->getRecord()->block_in_support_reason;
}
function getType(): int
{
return $this->getRecord()->type;
}
function getCoins(): float
{
if(!OPENVK_ROOT_CONF["openvk"]["preferences"]["commerce"])
return 0.0;
return $this->getRecord()->coins;
}
function getRating(): int
{
return OPENVK_ROOT_CONF["openvk"]["preferences"]["commerce"] ? $this->getRecord()->rating : 0;
}
function getReputation(): int
{
return $this->getRecord()->reputation;
}
function getRegistrationTime(): DateTime
{
return new DateTime($this->getRecord()->since->getTimestamp());
}
function getRegistrationIP(): string
{
return $this->getRecord()->registering_ip;
}
function getHometown(): ?string
{
return $this->getRecord()->hometown;
}
function getPoliticalViews(): int
{
return $this->getRecord()->polit_views;
}
function getMaritalStatus(): int
{
return $this->getRecord()->marital_status;
}
function getContactEmail(): ?string
{
return $this->getRecord()->email_contact;
}
function getTelegram(): ?string
{
return $this->getRecord()->telegram;
}
function getInterests(): ?string
{
return $this->getRecord()->interests;
}
function getFavoriteMusic(): ?string
{
return $this->getRecord()->fav_music;
}
function getFavoriteFilms(): ?string
{
return $this->getRecord()->fav_films;
}
function getFavoriteShows(): ?string
{
return $this->getRecord()->fav_shows;
}
function getFavoriteBooks(): ?string
{
return $this->getRecord()->fav_books;
}
function getFavoriteQuote(): ?string
{
return $this->getRecord()->fav_quote;
}
function getCity(): ?string
{
return $this->getRecord()->city;
}
function getPhysicalAddress(): ?string
{
return $this->getRecord()->address;
}
function getNotificationOffset(): int
{
return $this->getRecord()->notification_offset;
@ -332,7 +345,7 @@ class User extends RowModel
{
return (int)floor((time() - $this->getBirthday()->timestamp()) / YEAR);
}
function get2faSecret(): ?string
{
return $this->getRecord()["2fa_secret"];
@ -347,7 +360,7 @@ class User extends RowModel
{
$this->stateChanges("notification_offset", time());
}
function getLeftMenuItemStatus(string $id): bool
{
return (bool) bmask($this->getRecord()->left_menu, [
@ -364,7 +377,7 @@ class User extends RowModel
],
])->get($id);
}
function getPrivacySetting(string $id): int
{
return (int) bmask($this->getRecord()->privacy, [
@ -383,7 +396,7 @@ class User extends RowModel
],
])->get($id);
}
function getPrivacyPermission(string $permission, ?User $user = NULL): bool
{
$permStatus = $this->getPrivacySetting($permission);
@ -391,7 +404,7 @@ class User extends RowModel
return $permStatus === User::PRIVACY_EVERYONE;
else if($user->getId() === $this->getId())
return true;
switch($permStatus) {
case User::PRIVACY_ONLY_FRIENDS:
return $this->getSubscriptionStatus($user) === User::SUBSCRIPTION_MUTUAL;
@ -402,12 +415,12 @@ class User extends RowModel
return false;
}
}
function getProfileCompletenessReport(): object
{
$incompleteness = 0;
$unfilled = [];
if(!$this->getRecord()->status) {
$unfilled[] = "status";
$incompleteness += 15;
@ -428,46 +441,46 @@ class User extends RowModel
$unfilled[] = "interests";
$incompleteness += 20;
}
$total = max(100 - $incompleteness + $this->getRating(), 0);
if(ovkGetQuirk("profile.rating-bar-behaviour") === 0)
if ($total >= 100)
$percent = round(($total / 10**strlen(strval($total))) * 100, 0);
else
$percent = min($total, 100);
return (object) [
"total" => $total,
"percent" => $percent,
"unfilled" => $unfilled,
];
}
function getFriends(int $page = 1, int $limit = 6): \Traversable
{
return $this->_abstractRelationGenerator("get-friends", $page, $limit);
}
function getFriendsCount(): int
{
return $this->_abstractRelationCount("get-friends");
}
function getFollowers(int $page = 1, int $limit = 6): \Traversable
{
return $this->_abstractRelationGenerator("get-followers", $page, $limit);
}
function getFollowersCount(): int
{
return $this->_abstractRelationCount("get-followers");
}
function getSubscriptions(int $page = 1, int $limit = 6): \Traversable
{
return $this->_abstractRelationGenerator("get-subscriptions-user", $page, $limit);
}
function getSubscriptionsCount(): int
{
return $this->_abstractRelationCount("get-subscriptions-user");
@ -477,7 +490,7 @@ class User extends RowModel
{
return sizeof(DatabaseConnection::i()->getContext()->table("messages")->where(["recipient_id" => $this->getId(), "unread" => 1]));
}
function getClubs(int $page = 1, bool $admin = false): \Traversable
{
if($admin) {
@ -502,7 +515,7 @@ class User extends RowModel
}
}
}
function getClubCount(bool $admin = false): int
{
if($admin) {
@ -517,7 +530,7 @@ class User extends RowModel
return sizeof($sel);
}
}
function getPinnedClubs(): \Traversable
{
foreach($this->getRecord()->related("groups.owner")->where("owner_club_pinned", true) as $target) {
@ -558,16 +571,16 @@ class User extends RowModel
foreach($sel as $target) {
$target = (new Clubs)->get($target->event);
if(!$target) continue;
yield $target;
}
}
function getMeetingCount(): int
{
return sizeof($this->getRecord()->related("event_turnouts.user"));
}
function getGifts(int $page = 1, ?int $perPage = NULL): \Traversable
{
$gifts = $this->getRecord()->related("gift_user_relations.receiver")->order("sent DESC")->page($page, $perPage ?? OPENVK_DEFAULT_PER_PAGE);
@ -581,7 +594,7 @@ class User extends RowModel
];
}
}
function getGiftCount(): int
{
return sizeof($this->getRecord()->related("gift_user_relations.receiver"));
@ -616,9 +629,9 @@ class User extends RowModel
function use2faBackupCode(int $code): bool
{
return (bool) $this->getRecord()->related("2fa_backup_codes.owner")->where("code", $code)->delete();
return (bool) $this->getRecord()->related("2fa_backup_codes.owner")->where("code", $code)->delete();
}
function getSubscriptionStatus(User $user): int
{
$subbed = !is_null($this->getRecord()->related("subscriptions.follower")->where([
@ -629,51 +642,51 @@ class User extends RowModel
"model" => static::class,
"follower" => $user->getId(),
])->fetch());
if($subbed && $followed) return User::SUBSCRIPTION_MUTUAL;
if($subbed) return User::SUBSCRIPTION_INCOMING;
if($followed) return User::SUBSCRIPTION_OUTGOING;
return User::SUBSCRIPTION_ABSENT;
}
function getNotificationsCount(bool $archived = false): int
{
return (new Notifications)->getNotificationCountByUser($this, $this->getNotificationOffset(), $archived);
}
function getNotifications(int $page, bool $archived = false): \Traversable
{
return (new Notifications)->getNotificationsByUser($this, $this->getNotificationOffset(), $archived, $page);
}
function getPendingPhoneVerification(): ?ActiveRow
{
return $this->getRecord()->ref("number_verification", "id");
}
function getRefLinkId(): string
{
$hash = hash_hmac("Snefru", (string) $this->getId(), CHANDLER_ROOT_CONF["security"]["secret"], true);
return dechex($this->getId()) . " " . base64_encode($hash);
}
function getNsfwTolerance(): int
{
return $this->getRecord()->nsfw_tolerance;
}
function isFemale(): bool
{
return (bool) $this->getRecord()->sex;
}
function isVerified(): bool
{
return (bool) $this->getRecord()->verified;
}
function isBanned(): bool
{
return !is_null($this->getBanReason());
@ -683,22 +696,22 @@ class User extends RowModel
{
return !is_null($this->getBanInSupportReason());
}
function isOnline(): bool
{
return time() - $this->getRecord()->online <= 300;
}
function prefersNotToSeeRating(): bool
{
return !((bool) $this->getRecord()->show_rating);
}
function hasPendingNumberChange(): bool
{
return !is_null($this->getPendingPhoneVerification());
}
function gift(User $sender, Gift $gift, ?string $comment = NULL, bool $anonymous = false): void
{
DatabaseConnection::i()->getContext()->table("gift_user_relations")->insert([
@ -710,7 +723,7 @@ class User extends RowModel
"sent" => time(),
]);
}
function ban(string $reason, bool $deleteSubscriptions = true): void
{
if($deleteSubscriptions) {
@ -723,42 +736,42 @@ class User extends RowModel
);
$subs->delete();
}
$this->setBlock_Reason($reason);
$this->save();
}
function verifyNumber(string $code): bool
{
$ver = $this->getPendingPhoneVerification();
if(!$ver) return false;
try {
if(sodium_memcmp((string) $ver->code, $code) === -1) return false;
} catch(\SodiumException $ex) {
return false;
}
$this->setPhone($ver->number);
$this->save();
DatabaseConnection::i()->getContext()
->table("number_verification")
->where("user", $this->getId())
->delete();
return true;
}
function setFirst_Name(string $firstName): void
{
$firstName = mb_convert_case($firstName, MB_CASE_TITLE);
if(!preg_match('%^[\p{Lu}\p{Lo}]\p{Mn}?(?:[\p{L&}\p{Lo}]\p{Mn}?){1,16}$%u', $firstName))
throw new InvalidUserNameException;
$this->stateChanges("first_name", $firstName);
}
function setLast_Name(string $lastName): void
{
if(!empty($lastName))
@ -767,15 +780,15 @@ class User extends RowModel
if(!preg_match('%^[\p{Lu}\p{Lo}]\p{Mn}?([\p{L&}\p{Lo}]\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);
}
function setPrivacySetting(string $id, int $status): void
{
$this->stateChanges("privacy", bmask($this->changes["privacy"] ?? $this->getRecord()->privacy, [
@ -794,7 +807,7 @@ class User extends RowModel
],
])->set($id, $status)->toInteger());
}
function setLeftMenuItemStatus(string $id, bool $status): void
{
$mask = bmask($this->changes["left_menu"] ?? $this->getRecord()->left_menu, [
@ -810,10 +823,10 @@ class User extends RowModel
"poster",
],
])->set($id, (int) $status)->toInteger();
$this->stateChanges("left_menu", $mask);
}
function setShortCode(?string $code = NULL, bool $force = false): ?bool
{
if(!is_null($code)) {
@ -825,20 +838,20 @@ class User extends RowModel
return false;
if(\Chandler\MVC\Routing\Router::i()->getMatchingRoute("/$code")[0]->presenter !== "UnknownTextRouteStrategy")
return false;
$pClub = DatabaseConnection::i()->getContext()->table("groups")->where("shortcode", $code)->fetch();
if(!is_null($pClub))
return false;
}
$this->stateChanges("shortcode", $code);
return true;
}
function setPhoneWithVerification(string $phone): string
{
$code = unpack("S", openssl_random_pseudo_bytes(2))[1];
if($this->hasPendingNumberChange()) {
DatabaseConnection::i()->getContext()
->table("number_verification")
@ -849,10 +862,10 @@ class User extends RowModel
->table("number_verification")
->insert(["user" => $this->getId(), "number" => $phone, "code" => $code]);
}
return (string) $code;
}
# KABOBSQL temporary fix
# Tuesday, the 7th of January 2020 @ 22:43 <Menhera>: implementing quick fix to this problem and monitoring
# NOTICE: this is an ongoing conversation, add your comments just above this line. Thanks!
@ -860,10 +873,10 @@ class User extends RowModel
{
$this->stateChanges("shortcode", $this->getRecord()->shortcode); #fix KABOBSQL
$this->stateChanges("online", $time);
return true;
}
function adminNotify(string $message): bool
{
$admId = OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"];
@ -871,12 +884,12 @@ class User extends RowModel
return false;
else if(is_null($admin = (new Users)->get($admId)))
return false;
$cor = new Correspondence($admin, $this);
$msg = new Message;
$msg->setContent($message);
$cor->sendMessage($msg, true);
return true;
}
@ -903,7 +916,7 @@ class User extends RowModel
case 2:
return 2;
break;
default:
return 0;
break;

View file

@ -16,7 +16,9 @@
"erusev/parsedown": "dev-master",
"bhaktaraz/php-rss-generator": "dev-master",
"ext-simplexml": "*",
"symfony/console": "5.4.x-dev"
"symfony/console": "5.4.x-dev",
"wapmorgan/morphos": "dev-master",
"ext-sodium": "*"
},
"minimum-stability": "dev"
}

79
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": "878bd996183ccbb15637a7399ba03ab9",
"content-hash": "63feb555e36a6e7ab5a0a5ec71adecdd",
"packages": [
{
"name": "al/emoji-detector",
@ -2222,6 +2222,80 @@
},
"time": "2018-09-26T17:10:59+00:00"
},
{
"name": "wapmorgan/morphos",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/wapmorgan/Morphos.git",
"reference": "ec18034d4a439139902c769a64bb67e59e3402a8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/wapmorgan/Morphos/zipball/ec18034d4a439139902c769a64bb67e59e3402a8",
"reference": "ec18034d4a439139902c769a64bb67e59e3402a8",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8"
},
"suggest": {
"ext-readline": "For using interactive version of script"
},
"default-branch": true,
"type": "library",
"autoload": {
"files": [
"src/English/functions.php",
"src/Russian/functions.php"
],
"psr-4": {
"morphos\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Sergey Vanyushin",
"email": "wapmorgan@gmail.com",
"role": "developer"
}
],
"description": "A morphological solution for Russian and English language written completely in PHP. Provides classes to inflect personal names, geographical names, decline and pluralize nouns, generate cardinal and ordinal numerals, spell out money amounts and time.",
"homepage": "http://morphos.io",
"keywords": [
"Numerals",
"adjectives",
"cardinal",
"declension",
"english",
"geographical names",
"human-friendly",
"inflection",
"language",
"money",
"morphology",
"nouns",
"ordinal",
"personal names",
"pluralization",
"russian",
"spelling",
"time"
],
"support": {
"issues": "https://github.com/wapmorgan/Morphos/issues",
"source": "https://github.com/wapmorgan/Morphos/tree/master"
},
"time": "2021-11-22T09:15:18+00:00"
},
{
"name": "whichbrowser/parser",
"version": "dev-master",
@ -2356,7 +2430,8 @@
"vearutop/php-obscene-censor-rus": 20,
"erusev/parsedown": 20,
"bhaktaraz/php-rss-generator": 20,
"symfony/console": 20
"symfony/console": 20,
"wapmorgan/morphos": 20
},
"prefer-stable": false,
"prefer-lowest": false,