2020-03-30 04:56:35 +09:00
< ? php
// {{{ License
2020-07-01 01:26:40 +09:00
2020-05-21 01:53:53 +09:00
// This file is part of GNU social - https://www.gnu.org/software/social
2020-03-30 04:56:35 +09:00
//
// GNU social is free software: you can redistribute it and/or modify
2020-05-11 05:43:15 +09:00
// it under the terms of the GNU Affero General Public License as published by
2020-03-30 04:56:35 +09:00
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
2020-05-11 05:43:15 +09:00
// You should have received a copy of the GNU Affero General Public License
2020-03-30 04:56:35 +09:00
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
2020-07-01 01:26:40 +09:00
2020-03-30 04:56:35 +09:00
// }}}
namespace App\Entity ;
2020-08-29 05:16:26 +09:00
use App\Core\Cache ;
2020-08-15 14:47:45 +09:00
use App\Core\DB\DB ;
use App\Core\Entity ;
2020-08-20 00:31:52 +09:00
use App\Core\Event ;
2021-04-16 07:28:28 +09:00
use App\Core\VisibilityScope ;
2020-05-11 05:43:15 +09:00
use DateTimeInterface ;
2020-03-30 04:56:35 +09:00
/**
* Entity for notices
*
* @ category DB
* @ package GNUsocial
*
2021-02-20 08:29:43 +09:00
* @ author Hugo Sales < hugo @ hsal . es >
* @ copyright 2020 - 2021 Free Software Foundation , Inc http :// www . fsf . org
2020-03-30 04:56:35 +09:00
* @ license https :// www . gnu . org / licenses / agpl . html GNU AGPL v3 or later
*/
2021-09-06 22:29:07 +09:00
class Note extends Entity implements \JsonSerializable
2020-03-30 04:56:35 +09:00
{
2020-03-30 23:00:13 +09:00
// {{{ Autocode
2021-05-06 01:03:03 +09:00
// @codeCoverageIgnoreStart
2020-03-31 00:13:51 +09:00
private int $id ;
2020-08-13 10:35:01 +09:00
private int $gsactor_id ;
2020-03-31 00:13:51 +09:00
private ? string $content ;
2020-09-06 05:46:37 +09:00
private ? string $rendered ;
2020-03-31 00:13:51 +09:00
private ? int $reply_to ;
2020-07-01 03:20:50 +09:00
private ? bool $is_local ;
2020-03-31 00:13:51 +09:00
private ? string $source ;
private ? int $conversation ;
private ? int $repeat_of ;
2020-09-05 11:33:29 +09:00
private int $scope = 1 ;
2021-04-28 06:24:48 +09:00
private \DateTimeInterface $created ;
private \DateTimeInterface $modified ;
2020-03-31 00:13:51 +09:00
public function setId ( int $id ) : self
{
$this -> id = $id ;
return $this ;
}
2020-08-09 01:11:18 +09:00
2020-03-31 00:13:51 +09:00
public function getId () : int
{
return $this -> id ;
}
2021-02-21 06:01:08 +09:00
public function setGSActorId ( int $gsactor_id ) : self
2020-03-31 00:13:51 +09:00
{
2020-08-13 10:35:01 +09:00
$this -> gsactor_id = $gsactor_id ;
2020-03-31 00:13:51 +09:00
return $this ;
}
2020-08-09 01:11:18 +09:00
2021-02-21 06:01:08 +09:00
public function getGSActorId () : int
2020-03-31 00:13:51 +09:00
{
2020-08-13 10:35:01 +09:00
return $this -> gsactor_id ;
2020-03-31 00:13:51 +09:00
}
public function setContent ( ? string $content ) : self
{
$this -> content = $content ;
return $this ;
}
2020-08-09 01:11:18 +09:00
2020-03-31 00:13:51 +09:00
public function getContent () : ? string
{
return $this -> content ;
}
2020-09-06 05:46:37 +09:00
public function setRendered ( ? string $rendered ) : self
{
$this -> rendered = $rendered ;
return $this ;
}
public function getRendered () : ? string
{
return $this -> rendered ;
}
2020-03-31 00:13:51 +09:00
public function setReplyTo ( ? int $reply_to ) : self
{
$this -> reply_to = $reply_to ;
return $this ;
}
2020-08-09 01:11:18 +09:00
2020-03-31 00:13:51 +09:00
public function getReplyTo () : ? int
{
return $this -> reply_to ;
}
2020-07-01 03:20:50 +09:00
public function setIsLocal ( ? bool $is_local ) : self
2020-03-31 00:13:51 +09:00
{
$this -> is_local = $is_local ;
return $this ;
}
2020-08-09 01:11:18 +09:00
2020-07-01 03:20:50 +09:00
public function getIsLocal () : ? bool
2020-03-31 00:13:51 +09:00
{
return $this -> is_local ;
}
public function setSource ( ? string $source ) : self
{
$this -> source = $source ;
return $this ;
}
2020-08-09 01:11:18 +09:00
2020-03-31 00:13:51 +09:00
public function getSource () : ? string
{
return $this -> source ;
}
public function setConversation ( ? int $conversation ) : self
{
$this -> conversation = $conversation ;
return $this ;
}
2020-08-09 01:11:18 +09:00
2020-03-31 00:13:51 +09:00
public function getConversation () : ? int
{
return $this -> conversation ;
}
public function setRepeatOf ( ? int $repeat_of ) : self
{
$this -> repeat_of = $repeat_of ;
return $this ;
}
2020-08-09 01:11:18 +09:00
2020-03-31 00:13:51 +09:00
public function getRepeatOf () : ? int
{
return $this -> repeat_of ;
}
2020-09-05 11:33:29 +09:00
public function setScope ( int $scope ) : self
2020-03-31 00:13:51 +09:00
{
$this -> scope = $scope ;
return $this ;
}
2020-08-09 01:11:18 +09:00
2020-09-05 11:33:29 +09:00
public function getScope () : int
2020-03-31 00:13:51 +09:00
{
return $this -> scope ;
}
2021-05-06 01:03:03 +09:00
public function setCreated ( DateTimeInterface $created ) : self
2020-07-01 03:20:50 +09:00
{
$this -> created = $created ;
return $this ;
}
2020-08-09 01:11:18 +09:00
2021-05-06 01:03:03 +09:00
public function getCreated () : DateTimeInterface
2020-07-01 03:20:50 +09:00
{
return $this -> created ;
}
2021-05-06 01:03:03 +09:00
public function setModified ( DateTimeInterface $modified ) : self
2020-07-01 03:20:50 +09:00
{
$this -> modified = $modified ;
return $this ;
}
2020-08-09 01:11:18 +09:00
2021-05-06 01:03:03 +09:00
public function getModified () : DateTimeInterface
2020-07-01 03:20:50 +09:00
{
return $this -> modified ;
}
2021-05-06 01:03:03 +09:00
// @codeCoverageIgnoreEnd
2020-03-30 23:00:13 +09:00
// }}} Autocode
2020-03-30 04:56:35 +09:00
2020-08-15 14:47:45 +09:00
public function getActorNickname ()
{
2020-08-20 00:31:52 +09:00
return GSActor :: getNicknameFromId ( $this -> gsactor_id );
}
public function getAvatarUrl ()
{
$url = null ;
2021-04-18 10:17:57 +09:00
Event :: handle ( 'GetAvatarUrl' , [ $this -> getGSActorId (), & $url ]);
2020-08-20 00:31:52 +09:00
return $url ;
2020-08-15 14:47:45 +09:00
}
2021-04-11 07:32:47 +09:00
public static function getAllNotes ( int $noteScope ) : array
2020-12-03 07:57:32 +09:00
{
return DB :: sql ( 'select * from note n ' .
'where n.reply_to is null and (n.scope & :notescope) <> 0 ' .
'order by n.created DESC' ,
[ 'n' => 'App\Entity\Note' ],
[ 'notescope' => $noteScope ]
);
}
2020-08-15 14:47:45 +09:00
2020-08-29 05:16:26 +09:00
public function getAttachments () : array
{
return Cache :: get ( 'note-attachments-' . $this -> id , function () {
return DB :: dql (
2021-04-16 07:28:28 +09:00
'select att from App\Entity\Attachment att ' .
'join App\Entity\AttachmentToNote atn with atn.attachment_id = att.id ' .
'where atn.note_id = :note_id' ,
2020-08-29 05:16:26 +09:00
[ 'note_id' => $this -> id ]
);
});
}
2021-08-14 23:07:51 +09:00
public function getLinks () : array
{
return Cache :: get ( 'note-links-' . $this -> id , function () {
return DB :: dql (
'select l from App\Entity\Link l ' .
'join App\Entity\NoteToLink ntl with ntl.link_id = l.id ' .
'where ntl.note_id = :note_id' ,
[ 'note_id' => $this -> id ]
);
});
}
2020-08-29 05:16:26 +09:00
public function getReplies () : array
{
2020-09-07 06:34:36 +09:00
return Cache :: getList ( 'note-replies-' . $this -> id , function () {
return DB :: dql ( 'select n from App\Entity\Note n where n.reply_to = :id' , [ 'id' => $this -> id ]);
});
}
public function getReplyToNickname () : ? string
{
if ( ! empty ( $this -> reply_to )) {
return Cache :: get ( 'note-reply-to-' . $this -> id , function () {
return DB :: dql ( 'select g from App\Entity\Note n join ' .
'App\Entity\GSActor g with n.gsactor_id = g.id where n.reply_to = :reply' ,
[ 'reply' => $this -> reply_to ])[ 0 ] -> getNickname ();
});
}
return null ;
2020-08-29 05:16:26 +09:00
}
2020-11-07 04:47:15 +09:00
/**
* Whether this note is visible to the given actor
*/
2021-05-24 04:56:45 +09:00
public function isVisibleTo ( GSActor | LocalUser $a ) : bool
2020-09-11 07:27:23 +09:00
{
2021-04-16 07:28:28 +09:00
$scope = VisibilityScope :: create ( $this -> scope );
2020-09-11 07:27:23 +09:00
return $scope -> public
|| ( $scope -> follower
&& null != DB :: find ( 'follow' , [ 'follower' => $a -> getId (), 'followed' => $this -> gsactor_id ]))
|| ( $scope -> addressee
&& null != DB :: find ( 'notification' , [ 'activity_id' => $this -> id , 'gsactor_id' => $a -> getId ()]))
2021-08-19 01:27:51 +09:00
|| ( $scope -> group && [] != DB :: dql ( 'select m from group_member m ' .
'join group_inbox i with m.group_id = i.group_id ' .
'join note n with i.activity_id = n.id ' .
'where n.id = :note_id and m.gsactor_id = :actor_id' ,
[ 'note_id' => $this -> id , 'actor_id' => $a -> getId ()]));
2020-09-11 07:27:23 +09:00
}
2021-08-08 09:39:39 +09:00
public function jsonSerialize ()
{
return [
'content' => $this -> getContent (),
'author' => $this -> getGSActorId (),
];
}
2020-03-30 04:56:35 +09:00
public static function schemaDef () : array
{
2020-08-15 14:47:45 +09:00
return [
2020-08-13 08:57:22 +09:00
'name' => 'note' ,
2020-03-30 04:56:35 +09:00
'fields' => [
2021-02-23 06:34:59 +09:00
'id' => [ 'type' => 'serial' , 'not null' => true ],
2021-03-12 07:16:17 +09:00
'gsactor_id' => [ 'type' => 'int' , 'foreign key' => true , 'target' => 'GSActor.id' , 'multiplicity' => 'one to one' , 'not null' => true , 'description' => 'who made the note' ],
2021-02-23 06:34:59 +09:00
'content' => [ 'type' => 'text' , 'description' => 'note content' ],
'rendered' => [ 'type' => 'text' , 'description' => 'rendered note content, so we can keep the microtags (if not local)' ],
2021-03-12 07:16:17 +09:00
'reply_to' => [ 'type' => 'int' , 'foreign key' => true , 'target' => 'Note.id' , 'multiplicity' => 'one to one' , 'description' => 'note replied to, null if root of a conversation' ],
2021-02-23 06:34:59 +09:00
'is_local' => [ 'type' => 'bool' , 'description' => 'was this note generated by a local actor' ],
2021-03-22 21:14:09 +09:00
'source' => [ 'type' => 'varchar' , 'foreign key' => true , 'length' => 32 , 'target' => 'NoteSource.code' , 'multiplicity' => 'many to one' , 'description' => 'fkey to source of note, like "web", "im", or "clientname"' ],
2021-03-12 07:16:17 +09:00
'conversation' => [ 'type' => 'int' , 'foreign key' => true , 'target' => 'Conversation.id' , 'multiplicity' => 'one to one' , 'description' => 'the local conversation id' ],
'repeat_of' => [ 'type' => 'int' , 'foreign key' => true , 'target' => 'Note.id' , 'multiplicity' => 'one to one' , 'description' => 'note this is a repeat of' ],
2021-04-16 07:28:28 +09:00
'scope' => [ 'type' => 'int' , 'not null' => true , 'default' => VisibilityScope :: PUBLIC , 'description' => 'bit map for distribution scope; 0 = everywhere; 1 = this server only; 2 = addressees; 4 = groups; 8 = followers; 16 = messages; null = default' ],
2020-07-01 01:26:40 +09:00
'created' => [ 'type' => 'datetime' , 'not null' => true , 'default' => 'CURRENT_TIMESTAMP' , 'description' => 'date this record was created' ],
'modified' => [ 'type' => 'timestamp' , 'not null' => true , 'default' => 'CURRENT_TIMESTAMP' , 'description' => 'date this record was modified' ],
2020-03-30 04:56:35 +09:00
],
2021-02-23 06:34:59 +09:00
'primary key' => [ 'id' ],
'indexes' => [
2020-08-13 08:57:22 +09:00
'note_created_id_is_local_idx' => [ 'created' , 'is_local' ],
'note_gsactor_created_idx' => [ 'gsactor_id' , 'created' ],
'note_is_local_created_gsactor_idx' => [ 'is_local' , 'created' , 'gsactor_id' ],
'note_repeat_of_created_idx' => [ 'repeat_of' , 'created' ],
'note_conversation_created_idx' => [ 'conversation' , 'created' ],
'note_reply_to_idx' => [ 'reply_to' ],
2020-03-30 04:56:35 +09:00
],
2020-08-13 08:57:22 +09:00
'fulltext indexes' => [ 'notice_fulltext_idx' => [ 'content' ]],
2020-03-30 04:56:35 +09:00
];
}
}