mirror of https://github.com/movim/movim
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
621 lines
18 KiB
621 lines
18 KiB
<?php
|
|
|
|
namespace Modl;
|
|
|
|
use Respect\Validation\Validator;
|
|
|
|
use Movim\Picture;
|
|
|
|
class Postn extends Model
|
|
{
|
|
public $origin; // Where the post is comming from (jid or server)
|
|
public $node; // microblog or pubsub
|
|
public $nodeid; // the ID if the item
|
|
|
|
public $aname; // author name
|
|
public $aid; // author id
|
|
public $aemail; // author email
|
|
|
|
public $title; //
|
|
public $content; // The content
|
|
public $contentraw; // The raw content
|
|
public $contentcleaned; // The cleanned content
|
|
|
|
public $commentorigin;
|
|
public $commentnodeid;
|
|
|
|
public $published;
|
|
public $updated;
|
|
public $delay;
|
|
|
|
public $picture; // Tell if the post contain embeded pictures
|
|
|
|
public $lat;
|
|
public $lon;
|
|
|
|
public $links;
|
|
|
|
public $reply;
|
|
|
|
public $hash;
|
|
|
|
private $youtube;
|
|
|
|
public $open;
|
|
public $logo;
|
|
private $openlink;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->hash = md5(openssl_random_pseudo_bytes(5));
|
|
|
|
$this->_struct = '
|
|
{
|
|
"origin" :
|
|
{"type":"string", "size":64, "key":true },
|
|
"node" :
|
|
{"type":"string", "size":96, "key":true },
|
|
"nodeid" :
|
|
{"type":"string", "size":96, "key":true },
|
|
"aname" :
|
|
{"type":"string", "size":128 },
|
|
"aid" :
|
|
{"type":"string", "size":64 },
|
|
"aemail" :
|
|
{"type":"string", "size":64 },
|
|
"title" :
|
|
{"type":"text" },
|
|
"content" :
|
|
{"type":"text" },
|
|
"contentraw" :
|
|
{"type":"text" },
|
|
"contentcleaned" :
|
|
{"type":"text" },
|
|
"commentorigin" :
|
|
{"type":"string", "size":64 },
|
|
"commentnodeid" :
|
|
{"type":"string", "size":96 },
|
|
|
|
"open" :
|
|
{"type":"bool"},
|
|
|
|
"published" :
|
|
{"type":"date" },
|
|
"updated" :
|
|
{"type":"date" },
|
|
"delay" :
|
|
{"type":"date" },
|
|
|
|
"reply" :
|
|
{"type":"text" },
|
|
|
|
"lat" :
|
|
{"type":"string", "size":32 },
|
|
"lon" :
|
|
{"type":"string", "size":32 },
|
|
|
|
"links" :
|
|
{"type":"text" },
|
|
"picture" :
|
|
{"type":"text" },
|
|
"hash" :
|
|
{"type":"string", "size":128, "mandatory":true }
|
|
}';
|
|
|
|
parent::__construct();
|
|
}
|
|
|
|
private function getContent($contents)
|
|
{
|
|
$content = '';
|
|
|
|
foreach($contents as $c) {
|
|
switch($c->attributes()->type) {
|
|
case 'html':
|
|
case 'xhtml':
|
|
$dom = new \DOMDocument('1.0', 'utf-8');
|
|
$import = @dom_import_simplexml($c->children());
|
|
if($import == null) {
|
|
$import = dom_import_simplexml($c);
|
|
}
|
|
$element = $dom->importNode($import, true);
|
|
$dom->appendChild($element);
|
|
return (string)$dom->saveHTML();
|
|
break;
|
|
case 'text':
|
|
if(trim($c) != '') {
|
|
$this->__set('contentraw', trim($c));
|
|
}
|
|
break;
|
|
default :
|
|
$content = (string)$c;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $content;
|
|
}
|
|
|
|
private function getTitle($titles)
|
|
{
|
|
$title = '';
|
|
foreach($titles as $t) {
|
|
switch($t->attributes()->type) {
|
|
case 'html':
|
|
case 'xhtml':
|
|
$title = strip_tags((string)$t->children()->asXML());
|
|
break;
|
|
case 'text':
|
|
if(trim($t) != '') {
|
|
$title = trim($t);
|
|
}
|
|
break;
|
|
default :
|
|
$title = (string)$t;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $title;
|
|
}
|
|
|
|
public function set($item, $from, $delay = false, $node = false)
|
|
{
|
|
if($item->item)
|
|
$entry = $item->item;
|
|
else
|
|
$entry = $item;
|
|
|
|
if($from != '')
|
|
$this->__set('origin', $from);
|
|
|
|
if($node)
|
|
$this->__set('node', $node);
|
|
else
|
|
$this->__set('node', (string)$item->attributes()->node);
|
|
|
|
$this->__set('nodeid', (string)$entry->attributes()->id);
|
|
|
|
if($entry->entry->id)
|
|
$this->__set('nodeid', (string)$entry->entry->id);
|
|
|
|
// Get some informations on the author
|
|
if($entry->entry->author->name)
|
|
$this->__set('aname', (string)$entry->entry->author->name);
|
|
if($entry->entry->author->uri)
|
|
$this->__set('aid', substr((string)$entry->entry->author->uri, 5));
|
|
if($entry->entry->author->email)
|
|
$this->__set('aemail', (string)$entry->entry->author->email);
|
|
|
|
// Non standard support
|
|
if($entry->entry->source && $entry->entry->source->author->name)
|
|
$this->__set('aname', (string)$entry->entry->source->author->name);
|
|
if($entry->entry->source && $entry->entry->source->author->uri)
|
|
$this->__set('aid', substr((string)$entry->entry->source->author->uri, 5));
|
|
|
|
$this->__set('title', $this->getTitle($entry->entry->title));
|
|
|
|
// Content
|
|
if($entry->entry->summary && (string)$entry->entry->summary != '')
|
|
$summary = '<p class="summary">'.(string)$entry->entry->summary.'</p>';
|
|
else
|
|
$summary = '';
|
|
|
|
if($entry->entry && $entry->entry->content) {
|
|
$content = $this->getContent($entry->entry->content);
|
|
} elseif($summary == '')
|
|
$content = __('');
|
|
else
|
|
$content = '';
|
|
|
|
$content = $summary.$content;
|
|
|
|
if($entry->entry->updated)
|
|
$this->__set('updated', (string)$entry->entry->updated);
|
|
else
|
|
$this->__set('updated', gmdate(SQL::SQL_DATE));
|
|
|
|
if($entry->entry->published)
|
|
$this->__set('published', (string)$entry->entry->published);
|
|
elseif($entry->entry->updated)
|
|
$this->__set('published', (string)$entry->entry->updated);
|
|
else
|
|
$this->__set('published', gmdate(SQL::SQL_DATE));
|
|
|
|
if($delay)
|
|
$this->__set('delay', $delay);
|
|
|
|
// Tags parsing
|
|
if($entry->entry->category) {
|
|
$td = new \Modl\TagDAO;
|
|
$td->delete($this->__get('nodeid'));
|
|
|
|
if($entry->entry->category->count() == 1
|
|
&& isset($entry->entry->category->attributes()->term)) {
|
|
$tag = new \Modl\Tag;
|
|
$tag->nodeid = $this->__get('nodeid');
|
|
$tag->tag = strtolower((string)$entry->entry->category->attributes()->term);
|
|
$td->set($tag);
|
|
} else {
|
|
foreach($entry->entry->category as $cat) {
|
|
$tag = new \Modl\Tag;
|
|
$tag->nodeid = $this->__get('nodeid');
|
|
$tag->tag = strtolower((string)$cat->attributes()->term);
|
|
$td->set($tag);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!isset($this->commentorigin))
|
|
$this->__set('commentorigin', $this->origin);
|
|
|
|
$this->__set('content', trim($content));
|
|
$this->contentcleaned = purifyHTML(html_entity_decode($this->content));
|
|
|
|
if($entry->entry->geoloc) {
|
|
if($entry->entry->geoloc->lat != 0)
|
|
$this->__set('lat', (string)$entry->entry->geoloc->lat);
|
|
if($entry->entry->geoloc->lon != 0)
|
|
$this->__set('lon', (string)$entry->entry->geoloc->lon);
|
|
}
|
|
|
|
// We fill empty aid
|
|
if($this->isMicroblog() && empty($this->aid)) {
|
|
$this->__set('aid', $this->origin);
|
|
}
|
|
|
|
// We check if this is a reply
|
|
if($entry->entry->{'in-reply-to'}) {
|
|
$href = (string)$entry->entry->{'in-reply-to'}->attributes()->href;
|
|
$arr = explode(';', $href);
|
|
$reply = [
|
|
'origin' => substr($arr[0], 5, -1),
|
|
'node' => substr($arr[1], 5),
|
|
'nodeid' => substr($arr[2], 5)
|
|
];
|
|
|
|
$this->__set('reply', serialize($reply));
|
|
}
|
|
|
|
$extra = false;
|
|
// We try to extract a picture
|
|
$xml = \simplexml_load_string('<div>'.$this->contentcleaned.'</div>');
|
|
if($xml) {
|
|
$results = $xml->xpath('//img/@src');
|
|
|
|
$check = new \Movim\Task\CheckSmallPicture;
|
|
|
|
if(is_array($results) && !empty($results)) {
|
|
$extra = (string)$results[0];
|
|
|
|
return $check->run($extra)
|
|
->then(function($small) use($extra, $entry) {
|
|
if($small) $this->picture = $extra;
|
|
$this->setAttachments($entry->entry->link, $extra);
|
|
});
|
|
} else {
|
|
$results = $xml->xpath('//video/@poster');
|
|
if(is_array($results) && !empty($results)) {
|
|
$extra = (string)$results[0];
|
|
|
|
return $check->run($extra)
|
|
->then(function($small) use($extra, $entry) {
|
|
$this->picture = $extra;
|
|
$this->setAttachments($entry->entry->link, $extra);
|
|
});
|
|
}
|
|
}
|
|
|
|
$results = $xml->xpath('//a');
|
|
if(is_array($results) && !empty($results)) {
|
|
foreach($results as $link) {
|
|
$link->addAttribute('target', '_blank');
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->setAttachments($entry->entry->link, $extra);
|
|
|
|
return new \React\Promise\Promise(function($resolve) {
|
|
$resolve(true);
|
|
});
|
|
}
|
|
|
|
private function typeIsPicture($type)
|
|
{
|
|
return in_array($type, ['image/jpeg', 'image/png', 'image/jpg', 'image/gif']);
|
|
}
|
|
|
|
private function setAttachments($links, $extra = false)
|
|
{
|
|
$l = [];
|
|
|
|
foreach($links as $attachment) {
|
|
$enc = [];
|
|
$enc = (array)$attachment->attributes();
|
|
$enc = $enc['@attributes'];
|
|
array_push($l, $enc);
|
|
|
|
if($this->picture == null
|
|
&& isset($enc['type'])
|
|
&& $this->typeIsPicture($enc['type'])
|
|
/*&& isSmallPicture($enc['href'])*/) {
|
|
$this->picture = $enc['href'];
|
|
}
|
|
|
|
if($enc['rel'] == 'alternate'
|
|
&& Validator::url()->validate($enc['href'])) $this->open = true;
|
|
|
|
if((string)$attachment->attributes()->title == 'comments') {
|
|
$substr = explode('?',substr((string)$attachment->attributes()->href, 5));
|
|
$this->commentorigin = reset($substr);
|
|
$this->commentnodeid = substr((string)$substr[1], 36);
|
|
}
|
|
}
|
|
|
|
if($extra) {
|
|
array_push(
|
|
$l,
|
|
[
|
|
'rel' => 'enclosure',
|
|
'href' => $extra,
|
|
'type' => 'picture'
|
|
]);
|
|
}
|
|
|
|
if(!empty($l)) {
|
|
$this->links = serialize($l);
|
|
}
|
|
}
|
|
|
|
public function getAttachments()
|
|
{
|
|
$attachments = null;
|
|
$this->openlink = null;
|
|
|
|
if(isset($this->links)) {
|
|
$links = unserialize($this->links);
|
|
$attachments = [
|
|
'pictures' => [],
|
|
'files' => [],
|
|
'links' => []
|
|
];
|
|
|
|
foreach($links as $l) {
|
|
// If the href is not a valid URL we skip
|
|
if(!Validator::url()->validate($l['href'])) continue;
|
|
|
|
// Prepare the switch
|
|
$rel = isset($l['rel']) ? $l['rel'] : null;
|
|
switch($rel) {
|
|
case 'enclosure':
|
|
if($this->typeIsPicture($l['type'])) {
|
|
array_push($attachments['pictures'], $l);
|
|
} elseif($l['type'] != 'picture') {
|
|
array_push($attachments['files'], $l);
|
|
}
|
|
break;
|
|
|
|
case 'related':
|
|
if(preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $l['href'], $match)) {
|
|
$this->youtube = $match[1];
|
|
}
|
|
|
|
array_push(
|
|
$attachments['links'],
|
|
[
|
|
'href' => $l['href'],
|
|
'url' => parse_url($l['href']),
|
|
'rel' => 'related'
|
|
]
|
|
);
|
|
break;
|
|
|
|
case 'alternate':
|
|
default:
|
|
$this->openlink = $l['href'];
|
|
if(!$this->isMicroblog()) {
|
|
array_push(
|
|
$attachments['links'],
|
|
[
|
|
'href' => $l['href'],
|
|
'url' => parse_url($l['href']),
|
|
'rel' => 'alternate'
|
|
]
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(empty($attachments['pictures'])) unset($attachments['pictures']);
|
|
if(empty($attachments['files'])) unset($attachments['files']);
|
|
if(empty($attachments['links'])) unset($attachments['links']);
|
|
|
|
return $attachments;
|
|
}
|
|
|
|
public function getAttachment()
|
|
{
|
|
$attachments = $this->getAttachments();
|
|
|
|
foreach($attachments as $key => $group) {
|
|
foreach($group as $attachment) {
|
|
if(in_array($attachment['rel'], ['enclosure', 'related'])) {
|
|
return $attachment;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public function getPicture()
|
|
{
|
|
return $this->picture;
|
|
}
|
|
|
|
public function getYoutube()
|
|
{
|
|
return $this->youtube;
|
|
}
|
|
|
|
public function getPlace()
|
|
{
|
|
return (isset($this->lat, $this->lon) && $this->lat != '' && $this->lon != '');
|
|
}
|
|
|
|
public function getLogo()
|
|
{
|
|
$p = new Picture;
|
|
return $p->get($this->origin.$this->node, 120);
|
|
}
|
|
|
|
public function getUUID()
|
|
{
|
|
if(substr($this->nodeid, 10) == 'urn:uuid:') {
|
|
return $this->nodeid;
|
|
} else {
|
|
return 'urn:uuid:'.generateUUID($this->nodeid);
|
|
}
|
|
}
|
|
|
|
public function getRef()
|
|
{
|
|
return 'xmpp:'.$this->origin.'?;node='.$this->node.';item='.$this->nodeid;
|
|
}
|
|
|
|
public function isMine()
|
|
{
|
|
$user = new \User;
|
|
|
|
return ($this->aid == $user->getLogin()
|
|
|| $this->origin == $user->getLogin());
|
|
}
|
|
|
|
public function isPublic() {
|
|
return ($this->open);
|
|
}
|
|
|
|
public function isMicroblog()
|
|
{
|
|
return ($this->node == "urn:xmpp:microblog:0");
|
|
}
|
|
|
|
public function isEditable()
|
|
{
|
|
return ($this->contentraw != null || $this->links != null);
|
|
}
|
|
|
|
public function isShort()
|
|
{
|
|
return (strlen($this->contentcleaned) < 700);
|
|
}
|
|
|
|
public function isNSFW()
|
|
{
|
|
return (current(explode('.', $this->origin)) == 'nsfw');
|
|
}
|
|
|
|
public function isReply()
|
|
{
|
|
return isset($this->reply);
|
|
}
|
|
|
|
public function isRTL()
|
|
{
|
|
return isRTL($this->contentraw);
|
|
}
|
|
|
|
public function getReply()
|
|
{
|
|
if(!$this->reply) return;
|
|
|
|
$reply = unserialize($this->reply);
|
|
$pd = new \Modl\PostnDAO;
|
|
return $pd->get($reply['origin'], $reply['node'], $reply['nodeid']);
|
|
}
|
|
|
|
public function getPublicUrl()
|
|
{
|
|
return $this->openlink;
|
|
}
|
|
|
|
public function countComments()
|
|
{
|
|
$pd = new \Modl\PostnDAO;
|
|
return $pd->countComments($this->commentorigin, $this->commentnodeid);
|
|
}
|
|
|
|
public function getTags()
|
|
{
|
|
$td = new \Modl\TagDAO;
|
|
$tags = $td->getTags($this->nodeid);
|
|
if(is_array($tags)) {
|
|
return array_map(function($tag) { return $tag->tag; }, $tags);
|
|
}
|
|
}
|
|
|
|
public function getTagsImploded()
|
|
{
|
|
$tags = $this->getTags();
|
|
if(is_array($tags)) {
|
|
return implode(', ', $tags);
|
|
}
|
|
}
|
|
|
|
public function getNext()
|
|
{
|
|
$pd = new PostnDAO;
|
|
return $pd->getNext($this->origin, $this->node, $this->nodeid);
|
|
}
|
|
|
|
public function getPrevious()
|
|
{
|
|
$pd = new PostnDAO;
|
|
return $pd->getPrevious($this->origin, $this->node, $this->nodeid);
|
|
}
|
|
}
|
|
|
|
class ContactPostn extends Postn
|
|
{
|
|
public $jid;
|
|
|
|
public $fn;
|
|
public $name;
|
|
|
|
public $privacy;
|
|
|
|
public $phototype;
|
|
public $photobin;
|
|
|
|
public $nickname;
|
|
|
|
function getContact()
|
|
{
|
|
$c = new Contact;
|
|
$c->jid = $this->aid;
|
|
$c->fn = $this->fn;
|
|
$c->name = $this->name;
|
|
$c->nickname = $this->nickname;
|
|
$c->phototype = $this->phototype;
|
|
$c->photobin = $this->photobin;
|
|
|
|
return $c;
|
|
}
|
|
|
|
public function isRecycled()
|
|
{
|
|
return ($this->getContact()->jid
|
|
&& $this->node == 'urn:xmpp:microblog:0'
|
|
&& (strtolower($this->origin) != strtolower($this->getContact()->jid)));
|
|
}
|
|
|
|
public function isEditable()
|
|
{
|
|
return (
|
|
($this->contentraw != null || $this->links != null)
|
|
&& !$this->isRecycled());
|
|
}
|
|
}
|