$user->getId(),
"model" => static::class,
"target" => $this->getRecord()->id,
];
if ((sizeof(DB::i()->getContext()->table("likes")->where($searchData)) > 0) !== $liked) {
if ($this->getOwner(false)->getId() !== $user->getId() && !($this->getOwner() instanceof Club) && !$this instanceof Comment) {
(new LikeNotification($this->getOwner(false), $this, $user))->emit();
}
parent::setLike($liked, $user);
}
if ($depth < ovkGetQuirk("wall.repost-liking-recursion-limit")) {
foreach ($this->getChildren() as $attachment) {
if ($attachment instanceof Post) {
$attachment->setLikeRecursively($liked, $user, $depth + 1);
}
}
}
}
/**
* May return fake owner (group), if flags are [1, (*)]
*
* @param bool $honourFlags - check flags
*/
public function getOwner(bool $honourFlags = true, bool $real = false): RowModel
{
if ($honourFlags && $this->isPostedOnBehalfOfGroup()) {
if ($this->getRecord()->wall < 0) {
return (new Clubs())->get(abs($this->getRecord()->wall));
}
}
return parent::getOwner($real);
}
public function getPrettyId(): string
{
return $this->getRecord()->wall . "_" . $this->getVirtualId();
}
public function getTargetWall(): int
{
return $this->getRecord()->wall;
}
public function getWallOwner()
{
$w = $this->getRecord()->wall;
if ($w < 0) {
return (new Clubs())->get(abs($w));
}
return (new Users())->get($w);
}
public function getRepostCount(): int
{
return sizeof(
$this->getRecord()
->related("attachments.attachable_id")
->where("attachable_type", get_class($this))
);
}
public function isPinned(): bool
{
return (bool) $this->getRecord()->pinned;
}
public function hasSource(): bool
{
return $this->getRecord()->source != null;
}
public function getSource(bool $format = false)
{
$orig_source = $this->getRecord()->source;
if (!str_contains($orig_source, "https://") && !str_contains($orig_source, "http://")) {
$orig_source = "https://" . $orig_source;
}
if (!$format) {
return $orig_source;
}
return $this->formatLinks($orig_source);
}
public function setSource(string $source)
{
$result = check_copyright_link($source);
$this->stateChanges("source", $source);
}
public function resetSource()
{
$this->stateChanges("source", null);
}
public function getVkApiCopyright(): object
{
return (object) [
'id' => 0,
'link' => $this->getSource(false),
'name' => $this->getSource(false),
'type' => 'link',
];
}
public function isAd(): bool
{
return (bool) $this->getRecord()->ad;
}
public function isPostedOnBehalfOfGroup(): bool
{
return ($this->getRecord()->flags & 0b10000000) > 0;
}
public function isSigned(): bool
{
return ($this->getRecord()->flags & 0b01000000) > 0;
}
public function isDeactivationMessage(): bool
{
return (($this->getRecord()->flags & 0b00100000) > 0) && ($this->getRecord()->owner > 0);
}
public function isUpdateAvatarMessage(): bool
{
return (($this->getRecord()->flags & 0b00010000) > 0) && ($this->getRecord()->owner > 0);
}
public function isExplicit(): bool
{
return (bool) $this->getRecord()->nsfw;
}
public function isDeleted(): bool
{
return (bool) $this->getRecord()->deleted;
}
public function getOwnerPost(): int
{
return $this->getOwner(false)->getId();
}
public function getPlatform(bool $forAPI = false): ?string
{
$platform = $this->getRecord()->api_source_name;
if ($forAPI) {
switch ($platform) {
case 'openvk_refresh_android':
case 'openvk_legacy_android':
return 'android';
break;
case 'openvk_ios':
case 'openvk_legacy_ios':
return 'iphone';
break;
case 'windows_phone':
return 'wphone';
break;
case 'vika_touch': // кика хохотач ахахахаххахахахахах
case 'vk4me':
return 'mobile';
break;
case null:
return null;
break;
default:
return 'api';
break;
}
} else {
return $platform;
}
}
public function getPlatformDetails(): array
{
$clients = simplexml_load_file(OPENVK_ROOT . "/data/clients.xml");
foreach ($clients as $client) {
if ($client['tag'] == $this->getPlatform()) {
return [
"tag" => $client['tag'],
"name" => $client['name'],
"url" => $client['url'],
"img" => $client['img'],
];
break;
}
}
return [
"tag" => $this->getPlatform(),
"name" => null,
"url" => null,
"img" => null,
];
}
public function getPostSourceInfo(): array
{
$post_source = ["type" => "vk"];
if ($this->getPlatform(true) !== null) {
$post_source = [
"type" => "api",
"platform" => $this->getPlatform(true),
];
}
if ($this->isUpdateAvatarMessage()) {
$post_source['data'] = 'profile_photo';
}
return $post_source;
}
public function getVkApiType(): string
{
$type = 'post';
if ($this->getSuggestionType() != 0) {
$type = 'suggest';
}
return $type;
}
public function pin(): void
{
DB::i()
->getContext()
->table("posts")
->where([
"wall" => $this->getTargetWall(),
"pinned" => true,
])
->update(["pinned" => false]);
$this->stateChanges("pinned", true);
$this->save();
}
public function unpin(): void
{
$this->stateChanges("pinned", false);
$this->save();
}
public function canBePinnedBy(User $user = null): bool
{
if (!$user) {
return false;
}
if ($this->getTargetWall() < 0) {
return (new Clubs())->get(abs($this->getTargetWall()))->canBeModifiedBy($user);
}
return $this->getTargetWall() === $user->getId();
}
public function canBeDeletedBy(User $user = null): bool
{
if (!$user) {
return false;
}
if ($this->getTargetWall() < 0 && !$this->getWallOwner()->canBeModifiedBy($user) && $this->getWallOwner()->getWallType() != 1 && $this->getSuggestionType() == 0) {
return false;
}
return $this->getOwnerPost() === $user->getId() || $this->canBePinnedBy($user);
}
public function setContent(string $content): void
{
if (ctype_space($content)) {
throw new \LengthException("Content length must be at least 1 character (not counting whitespaces).");
} elseif (iconv_strlen($content) > OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["maxSize"]) {
throw new \LengthException("Content is too large.");
}
$this->stateChanges("content", $content);
}
public function toggleLike(User $user): bool
{
$liked = parent::toggleLike($user);
if (!$user->isPrivateLikes() && $this->getOwner(false)->getId() !== $user->getId() && !($this->getOwner() instanceof Club) && !$this instanceof Comment) {
(new LikeNotification($this->getOwner(false), $this, $user))->emit();
}
foreach ($this->getChildren() as $attachment) {
if ($attachment instanceof Post) {
$attachment->setLikeRecursively($liked, $user, 2);
}
}
return $liked;
}
public function setLike(bool $liked, User $user): void
{
$this->setLikeRecursively($liked, $user, 1);
}
public function deletePost(): void
{
$this->setDeleted(1);
$this->unwire();
$this->save();
}
public function canBeViewedBy(?User $user = null): bool
{
if ($this->isDeleted()) {
return false;
}
return $this->getWallOwner()->canBeViewedBy($user);
}
public function getSuggestionType()
{
return $this->getRecord()->suggested;
}
public function getPageURL(): string
{
return "/wall" . $this->getPrettyId();
}
public function toNotifApiStruct()
{
$res = (object) [];
$res->id = $this->getVirtualId();
$res->to_id = $this->getOwner() instanceof Club ? $this->getOwner()->getId() * -1 : $this->getOwner()->getId();
$res->from_id = $res->to_id;
$res->date = $this->getPublicationTime()->timestamp();
$res->text = $this->getText(false);
$res->attachments = []; # todo
$res->copy_owner_id = null; # todo
$res->copy_post_id = null; # todo
return $res;
}
public function canBeEditedBy(?User $user = null): bool
{
if (!$user) {
return false;
}
if ($this->isDeactivationMessage() || $this->isUpdateAvatarMessage()) {
return false;
}
if ($this->getTargetWall() > 0) {
return $this->getPublicationTime()->timestamp() + WEEK > time() && $user->getId() == $this->getOwner(false)->getId();
} else {
if ($this->isPostedOnBehalfOfGroup()) {
return $this->getWallOwner()->canBeModifiedBy($user);
} else {
return $user->getId() == $this->getOwner(false)->getId();
}
}
return $user->getId() == $this->getOwner(false)->getId();
}
public function toRss(): \Bhaktaraz\RSSGenerator\Item
{
$domain = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
$description = $this->getText(false);
$title = str_replace("\n", "", ovk_proc_strtr($description, 79));
$description_html = $description;
$url = $domain . "/wall" . $this->getPrettyId();
if ($this->isUpdateAvatarMessage()) {
$title = tr('upd_in_general');
}
if ($this->isDeactivationMessage()) {
$title = tr('post_deact_in_general');
}
$author = $this->getOwner();
$target_wall = $this->getWallOwner();
$author_name = escape_html($author->getCanonicalName());
if ($this->isExplicit()) {
$title = 'NSFW: ' . $title;
}
foreach ($this->getChildren() as $child) {
if ($child instanceof Photo) {
$child_page = $domain . $child->getPageURL();
$child_url = $child->getURL();
$description_html .= "
";
} elseif ($child instanceof Video) {
$child_page = $domain . '/video' . $child->getPrettyId();
if ($child->getType() != 1) {
$description_html .= "" .
"
" .
"
" .
"" . escape_html($child->getName()) . "
";
} else {
$description_html .= "" .
"
" .
"getVideoDriver()->getURL() . "\">" . escape_html($child->getName()) . "
";
}
} elseif ($child instanceof Audio) {
if (!$child->isWithdrawn()) {
$description_html .= "
"
. "" . escape_html($child->getName()) . ":"
. "
"
. ""
. "
";
}
} elseif ($child instanceof Poll) {
$description_html .= "
" . tr('poll') . ": " . escape_html($child->getTitle());
} elseif ($child instanceof Note) {
$description_html .= "
" . tr('note') . ": " . escape_html($child->getName());
}
}
$description_html .= "
" . tr('author') . ": " . $author_name . "";
if ($target_wall->getRealId() != $author->getRealId()) {
$description_html .= "
" . tr('on_wall') . ": " . escape_html($target_wall->getCanonicalName()) . "";
}
if ($this->isSigned()) {
$signer = $this->getOwner(false);
$description_html .= "
" . tr('sign_short') . ": " . escape_html($signer->getCanonicalName()) . "";
}
if ($this->hasSource()) {
$description_html .= "
" . tr('source') . ": " . escape_html($this->getSource());
}
$item = new \Bhaktaraz\RSSGenerator\Item();
$item->title($title)
->url($url)
->guid($url)
->creator($author_name)
->pubDate($this->getPublicationTime()->timestamp())
->content(str_replace("\n", "
", $description_html));
return $item;
}
public function getGeo(): ?object
{
if (!$this->getRecord()->geo) {
return null;
}
return (object) json_decode($this->getRecord()->geo, true, JSON_UNESCAPED_UNICODE);
}
public function setGeo($encoded_object): void
{
$final_geo = $encoded_object['name'];
$neutral_names = ["Россия", "Russia", "Росія", "Россія", "Украина", "Ukraine", "Україна", "Украіна"];
foreach ($neutral_names as $name) {
if (str_contains($final_geo, $name . ", ")) {
$final_geo = str_replace($name . ", ", "", $final_geo);
}
}
$encoded_object['name'] = ovk_proc_strtr($final_geo, 255);
$encoded = json_encode($encoded_object);
$this->stateChanges("geo", $encoded);
}
public function getLat(): ?float
{
return (float) $this->getRecord()->geo_lat ?? null;
}
public function getLon(): ?float
{
return (float) $this->getRecord()->geo_lon ?? null;
}
public function getVkApiGeo(): object
{
return (object) [
'type' => 'point',
'coordinates' => $this->getLat() . ',' . $this->getLon(),
'name' => $this->getGeo()->name,
];
}
}