openvk/Web/Models/Entities/Post.php

419 lines
12 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php declare(strict_types=1);
namespace openvk\Web\Models\Entities;
use Chandler\Database\DatabaseConnection as DB;
use openvk\Web\Models\Repositories\{Clubs, Users};
use openvk\Web\Models\RowModel;
use openvk\Web\Models\Entities\Notifications\LikeNotification;
class Post extends Postable
{
protected $tableName = "posts";
protected $upperNodeReferenceColumnName = "wall";
private function setLikeRecursively(bool $liked, User $user, int $depth): void
{
$searchData = [
"origin" => $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
*/
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);
}
function getPrettyId(): string
{
return $this->getRecord()->wall . "_" . $this->getVirtualId();
}
function getTargetWall(): int
{
return $this->getRecord()->wall;
}
function getWallOwner()
{
$w = $this->getRecord()->wall;
if($w < 0)
return (new Clubs)->get(abs($w));
return (new Users)->get($w);
}
function getRepostCount(): int
{
return sizeof(
$this->getRecord()
->related("attachments.attachable_id")
->where("attachable_type", get_class($this))
);
}
function isPinned(): bool
{
return (bool) $this->getRecord()->pinned;
}
function hasSource(): bool
{
return $this->getRecord()->source != NULL;
}
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);
}
function setSource(string $source)
{
$result = check_copyright_link($source);
$this->stateChanges("source", $source);
}
function resetSource()
{
$this->stateChanges("source", NULL);
}
function getVkApiCopyright(): object
{
return (object)[
'id' => 0,
'link' => $this->getSource(false),
'name' => $this->getSource(false),
'type' => 'link',
];
}
function isAd(): bool
{
return (bool) $this->getRecord()->ad;
}
function isPostedOnBehalfOfGroup(): bool
{
return ($this->getRecord()->flags & 0b10000000) > 0;
}
function isSigned(): bool
{
return ($this->getRecord()->flags & 0b01000000) > 0;
}
function isDeactivationMessage(): bool
{
return (($this->getRecord()->flags & 0b00100000) > 0) && ($this->getRecord()->owner > 0);
}
function isUpdateAvatarMessage(): bool
{
return (($this->getRecord()->flags & 0b00010000) > 0) && ($this->getRecord()->owner > 0);
}
function isExplicit(): bool
{
return (bool) $this->getRecord()->nsfw;
}
function isDeleted(): bool
{
return (bool) $this->getRecord()->deleted;
}
function getOwnerPost(): int
{
return $this->getOwner(false)->getId();
}
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;
}
}
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
];
}
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;
}
function getVkApiType(): string
{
$type = 'post';
if($this->getSuggestionType() != 0)
$type = 'suggest';
return $type;
}
function pin(): void
{
DB::i()
->getContext()
->table("posts")
->where([
"wall" => $this->getTargetWall(),
"pinned" => true,
])
->update(["pinned" => false]);
$this->stateChanges("pinned", true);
$this->save();
}
function unpin(): void
{
$this->stateChanges("pinned", false);
$this->save();
}
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();
}
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);
}
function setContent(string $content): void
{
if(ctype_space($content))
throw new \LengthException("Content length must be at least 1 character (not counting whitespaces).");
else if(iconv_strlen($content) > OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["maxSize"])
throw new \LengthException("Content is too large.");
$this->stateChanges("content", $content);
}
function toggleLike(User $user): bool
{
$liked = parent::toggleLike($user);
if($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;
}
function setLike(bool $liked, User $user): void
{
$this->setLikeRecursively($liked, $user, 1);
}
function deletePost(): void
{
$this->setDeleted(1);
$this->unwire();
$this->save();
}
function canBeViewedBy(?User $user = NULL): bool
{
if($this->isDeleted()) {
return false;
}
return $this->getWallOwner()->canBeViewedBy($user);
}
function getSuggestionType()
{
return $this->getRecord()->suggested;
}
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;
}
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();
}
function toRss(): \Bhaktaraz\RSSGenerator\Item
{
$domain = ovk_scheme(true).$_SERVER["HTTP_HOST"];
$description = $this->getText(false);
$description_html = $description;
$url = $domain."/wall".$this->getPrettyId();
$author = $this->getOwner();
$author_name = htmlspecialchars($author->getCanonicalName(), ENT_DISALLOWED | ENT_XHTML);
if($this->isExplicit())
$description_html .= "<br /><b>".tr('contains_nsfw').".</b><br />";
foreach($this->getChildren() as $child) {
if($child instanceof Photo) {
$child_page = $domain.$child->getPageURL();
$child_url = $child->getURLBySizeId('large');
$description_html .= "<br /><a href='$child_page'><img src='$child_url'></a>";
} elseif($child instanceof Video) {
$child_page = $domain.'/video'.$child->getPrettyId();
$description_html .= "<br /><a href='$child_page'>Video</a>";
} elseif($child instanceof Audio) {
$description_html .= "<br />Audio";
}
}
$description_html .= "<br />".tr('author').": <img width='15px' src='".$author->getAvatarURL()."'><a href='".$author->getURL()."'>" . $author_name . "</a>";
if($this->hasSource()) {
$description_html .= "<br />".tr('source').": ".htmlspecialchars($this->getSource(), ENT_DISALLOWED | ENT_XHTML);
}
$item = new \Bhaktaraz\RSSGenerator\Item();
$item->title(str_replace("\n", "", ovk_proc_strtr($description, 79)))
->url($url)
->guid($url)
->creator($author_name)
->pubDate($this->getPublicationTime()->timestamp())
->content(str_replace("\n", "<br />", $description_html));
return $item;
}
use Traits\TRichText;
}