2020-03-29 20:56:35 +01:00
< ? php
2021-10-21 13:49:41 +01:00
declare ( strict_types = 1 );
2020-03-29 20:56:35 +01:00
// {{{ License
2020-06-30 17:26:40 +01:00
2020-05-20 17:53:53 +01:00
// This file is part of GNU social - https://www.gnu.org/software/social
2020-03-29 20:56:35 +01:00
//
// GNU social is free software: you can redistribute it and/or modify
2020-05-10 21:43:15 +01:00
// it under the terms of the GNU Affero General Public License as published by
2020-03-29 20:56:35 +01: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-10 21:43:15 +01:00
// You should have received a copy of the GNU Affero General Public License
2020-03-29 20:56:35 +01:00
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
2020-06-30 17:26:40 +01:00
2020-03-29 20:56:35 +01:00
// }}}
namespace App\Entity ;
2020-08-28 21:16:26 +01:00
use App\Core\Cache ;
2020-08-15 06:47:45 +01:00
use App\Core\DB\DB ;
use App\Core\Entity ;
2021-11-27 04:12:44 +00:00
use App\Core\Event ;
2021-12-26 19:50:21 +00:00
use App\Core\Log ;
2021-12-23 17:15:35 +00:00
use App\Core\Router\Router ;
2021-04-15 23:28:28 +01:00
use App\Core\VisibilityScope ;
2022-01-03 20:31:39 +00:00
use App\Util\Exception\ClientException ;
use App\Util\Exception\NoSuchNoteException ;
2021-12-21 16:04:50 +00:00
use App\Util\Formatting ;
2021-09-18 04:54:35 +01:00
use Component\Avatar\Avatar ;
2021-12-23 17:15:35 +00:00
use Component\Conversation\Entity\Conversation ;
2021-12-25 20:27:10 +00:00
use Component\Language\Entity\Language ;
2022-01-03 20:31:39 +00:00
use function App\Core\I18n\_m ;
2020-05-10 21:43:15 +01:00
2020-03-29 20:56:35 +01:00
/**
* Entity for notices
*
* @ category DB
* @ package GNUsocial
*
2021-02-19 23:29:43 +00:00
* @ author Hugo Sales < hugo @ hsal . es >
* @ copyright 2020 - 2021 Free Software Foundation , Inc http :// www . fsf . org
2020-03-29 20:56:35 +01:00
* @ license https :// www . gnu . org / licenses / agpl . html GNU AGPL v3 or later
*/
2021-09-09 03:46:30 +01:00
class Note extends Entity
2020-03-29 20:56:35 +01:00
{
2020-03-30 15:00:13 +01:00
// {{{ Autocode
2021-05-05 17:03:03 +01:00
// @codeCoverageIgnoreStart
2020-03-30 16:13:51 +01:00
private int $id ;
2021-09-18 03:22:27 +01:00
private int $actor_id ;
2021-12-26 21:32:09 +00:00
private ? string $content = null ;
2021-12-10 18:23:03 +00:00
private string $content_type = 'text/plain' ;
2021-12-26 21:32:09 +00:00
private ? string $rendered = null ;
2021-12-10 18:23:03 +00:00
private int $conversation_id ;
2021-12-26 16:51:36 +00:00
private ? int $reply_to = null ;
2021-11-16 23:24:06 +00:00
private bool $is_local ;
2021-12-26 21:32:09 +00:00
private ? string $source = null ;
private int $scope = 1 ; //VisibilityScope::EVERYWHERE->value;
private ? string $url = null ;
private ? int $language_id = null ;
2021-12-26 15:12:06 +00:00
private \DateTimeInterface $created ;
private \DateTimeInterface $modified ;
2020-03-30 16:13:51 +01:00
public function setId ( int $id ) : self
{
$this -> id = $id ;
return $this ;
}
2020-08-08 17:11:18 +01:00
2020-03-30 16:13:51 +01:00
public function getId () : int
{
return $this -> id ;
}
2021-09-18 03:22:27 +01:00
public function setActorId ( int $actor_id ) : self
2020-03-30 16:13:51 +01:00
{
2021-09-18 03:22:27 +01:00
$this -> actor_id = $actor_id ;
2020-03-30 16:13:51 +01:00
return $this ;
}
2020-08-08 17:11:18 +01:00
2021-09-18 03:22:27 +01:00
public function getActorId () : int
2020-03-30 16:13:51 +01:00
{
2021-09-18 03:22:27 +01:00
return $this -> actor_id ;
2020-03-30 16:13:51 +01:00
}
2021-12-10 18:23:03 +00:00
public function setContent ( ? string $content ) : self
2021-09-09 03:46:30 +01:00
{
2021-12-10 18:23:03 +00:00
$this -> content = $content ;
return $this ;
2021-09-09 03:46:30 +01:00
}
2021-12-10 18:23:03 +00:00
public function getContent () : ? string
2021-09-09 03:46:30 +01:00
{
2021-12-10 18:23:03 +00:00
return $this -> content ;
2021-09-09 03:46:30 +01:00
}
2021-12-10 18:23:03 +00:00
public function setContentType ( string $content_type ) : self
2020-03-30 16:13:51 +01:00
{
2021-12-26 15:12:06 +00:00
$this -> content_type = \mb_substr ( $content_type , 0 , 129 );
2020-03-30 16:13:51 +01:00
return $this ;
}
2020-08-08 17:11:18 +01:00
2021-12-10 18:23:03 +00:00
public function getContentType () : string
2020-03-30 16:13:51 +01:00
{
2021-12-10 18:23:03 +00:00
return $this -> content_type ;
2020-03-30 16:13:51 +01:00
}
2020-09-05 21:46:37 +01:00
public function setRendered ( ? string $rendered ) : self
{
$this -> rendered = $rendered ;
return $this ;
}
public function getRendered () : ? string
{
return $this -> rendered ;
}
2021-12-10 18:23:03 +00:00
public function setConversationId ( int $conversation_id ) : self
{
$this -> conversation_id = $conversation_id ;
return $this ;
}
public function getConversationId () : int
{
return $this -> conversation_id ;
}
2021-12-08 22:46:00 +00:00
public function setReplyTo ( ? int $reply_to ) : self
{
$this -> reply_to = $reply_to ;
return $this ;
}
public function getReplyTo () : ? int
{
2021-12-10 18:23:03 +00:00
return $this -> reply_to ;
2021-12-08 22:46:00 +00:00
}
2021-11-16 23:24:06 +00:00
public function setIsLocal ( bool $is_local ) : self
2020-03-30 16:13:51 +01:00
{
$this -> is_local = $is_local ;
return $this ;
}
2020-08-08 17:11:18 +01:00
2021-11-16 23:24:06 +00:00
public function getIsLocal () : bool
2020-03-30 16:13:51 +01:00
{
return $this -> is_local ;
}
public function setSource ( ? string $source ) : self
{
2021-12-26 21:32:09 +00:00
$this -> source = \is_null ( $source ) ? null : \mb_substr ( $source , 0 , 32 );
2020-03-30 16:13:51 +01:00
return $this ;
}
2020-08-08 17:11:18 +01:00
2020-03-30 16:13:51 +01:00
public function getSource () : ? string
{
return $this -> source ;
}
2021-12-26 17:31:53 +00:00
public function setScope ( VisibilityScope | int $scope ) : self
2020-03-30 16:13:51 +01:00
{
2021-12-26 17:31:53 +00:00
$this -> scope = is_int ( $scope ) ? $scope : $scope -> value ;
2020-03-30 16:13:51 +01:00
return $this ;
}
2020-08-08 17:11:18 +01:00
2021-12-26 17:31:53 +00:00
public function getScope () : VisibilityScope
2020-03-30 16:13:51 +01:00
{
2021-12-26 17:31:53 +00:00
return VisibilityScope :: from ( $this -> scope );
2020-03-30 16:13:51 +01:00
}
2021-12-10 18:23:03 +00:00
public function setUrl ( ? string $url ) : self
2021-10-04 17:00:58 +01:00
{
$this -> url = $url ;
return $this ;
}
2021-12-10 18:23:03 +00:00
public function getUrl () : ? string
2021-10-21 13:49:41 +01:00
{
2021-12-10 18:23:03 +00:00
return $this -> url ;
2021-10-21 13:49:41 +01:00
}
2021-11-27 15:06:46 +00:00
public function setLanguageId ( ? int $language_id ) : self
2021-10-21 13:49:41 +01:00
{
2021-11-24 15:51:01 +00:00
$this -> language_id = $language_id ;
2021-10-21 13:49:41 +01:00
return $this ;
}
2021-12-10 18:23:03 +00:00
public function getLanguageId () : ? int
{
return $this -> language_id ;
}
2021-12-26 15:12:06 +00:00
public function setCreated ( \DateTimeInterface $created ) : self
2020-06-30 19:20:50 +01:00
{
$this -> created = $created ;
return $this ;
}
2020-08-08 17:11:18 +01:00
2021-12-26 15:12:06 +00:00
public function getCreated () : \DateTimeInterface
2020-06-30 19:20:50 +01:00
{
return $this -> created ;
}
2021-12-26 15:12:06 +00:00
public function setModified ( \DateTimeInterface $modified ) : self
2020-06-30 19:20:50 +01:00
{
$this -> modified = $modified ;
return $this ;
}
2020-08-08 17:11:18 +01:00
2021-12-26 15:12:06 +00:00
public function getModified () : \DateTimeInterface
2020-06-30 19:20:50 +01:00
{
return $this -> modified ;
}
2021-05-05 17:03:03 +01:00
// @codeCoverageIgnoreEnd
2020-03-30 15:00:13 +01:00
// }}} Autocode
2020-03-29 20:56:35 +01:00
2022-01-03 20:31:39 +00:00
public static function cacheKeys ( int $note_id )
{
return [
'note' => " note- { $note_id } " ,
'attachments' => " note-attachments- { $note_id } " ,
'attachments-title' => " note-attachments-with-title- { $note_id } " ,
'links' => " note-links- { $note_id } " ,
'tags' => " note-tags- { $note_id } " ,
'replies' => " note-replies- { $note_id } " ,
];
}
2021-12-23 17:15:35 +00:00
public function getConversation () : Conversation
{
return Conversation :: getByPK ([ 'id' => $this -> getConversationId ()]);
}
public function getConversationUrl ( int $type = Router :: ABSOLUTE_URL ) : ? string
{
return Router :: url ( 'conversation' , [ 'conversation_id' => $this -> getConversationId ()], $type );
}
public function getConversationUri () : string
{
return $this -> getConversationUrl ( type : Router :: ABSOLUTE_URL );
}
2021-09-18 03:22:27 +01:00
public function getActor () : Actor
2021-09-14 13:40:50 +01:00
{
2022-01-02 20:37:15 +00:00
return Actor :: getById ( $this -> getActorId ());
2021-09-14 13:40:50 +01:00
}
public function getActorNickname () : string
2020-08-15 06:47:45 +01:00
{
2022-01-02 20:37:15 +00:00
return Actor :: getNicknameById ( $this -> getActorId ());
2020-08-19 16:31:52 +01:00
}
2021-10-29 22:05:10 +01:00
public function getActorFullname () : ? string
2021-10-26 14:47:28 +01:00
{
2022-01-02 20:37:15 +00:00
return Actor :: getFullnameById ( $this -> getActorId ());
2021-10-26 14:47:28 +01:00
}
2021-12-27 04:47:04 +00:00
public function getActorAvatarUrl ( string $size = 'medium' ) : string
2020-08-19 16:31:52 +01:00
{
2021-12-04 11:56:27 +00:00
return Avatar :: getUrl ( $this -> getActorId (), $size );
}
2021-12-04 19:58:00 +00:00
public static function getById ( int $note_id ) : self
2021-12-04 11:56:27 +00:00
{
2022-01-03 20:31:39 +00:00
return Cache :: get ( self :: cacheKeys ( $note_id )[ 'note' ], fn () => DB :: findOneBy ( 'note' , [ 'id' => $note_id ]));
2020-08-15 06:47:45 +01:00
}
2021-12-01 21:41:41 +00:00
2021-12-05 21:03:13 +00:00
public function getNoteLanguageShortDisplay () : ? string
2021-12-02 15:05:23 +00:00
{
2022-01-03 20:31:39 +00:00
return ! \is_null ( $this -> getLanguageId ()) ? Language :: getById ( $this -> getLanguageId ()) -> getShortDisplay () : null ;
2021-12-02 15:05:23 +00:00
}
2021-12-05 21:03:13 +00:00
public function getLanguageLocale () : ? string
2021-12-02 15:05:23 +00:00
{
2022-01-03 20:31:39 +00:00
return ! \is_null ( $this -> getLanguageId ()) ? Language :: getById ( $this -> getLanguageId ()) -> getLocale () : null ;
2021-12-02 15:05:23 +00:00
}
2022-02-04 16:03:49 +00:00
public function getRenderedSplit () : array
{
return preg_split ( '/(<\s*p\s*\/?>)|(<\s*br\s*\/?>)|(\s\s+)|(<\s*\/p\s*\/?>)/' , $this -> getRendered (), - 1 , PREG_SPLIT_NO_EMPTY );
}
2021-12-01 21:41:41 +00:00
public static function getAllNotesByActor ( Actor $actor ) : array
{
2021-12-23 13:27:31 +00:00
return DB :: findBy ( 'note' , [ 'actor_id' => $actor -> getId ()], order_by : [ 'created' => 'DESC' , 'id' => 'DESC' ]);
2020-12-02 22:57:32 +00:00
}
2020-08-15 06:47:45 +01:00
2020-08-28 21:16:26 +01:00
public function getAttachments () : array
{
2022-01-03 20:31:39 +00:00
return Cache :: getList ( self :: cacheKeys ( $this -> getId ())[ 'attachments' ], function () {
2020-08-28 21:16:26 +01:00
return DB :: dql (
2021-11-09 23:37:46 +00:00
<<< 'EOF'
select att from attachment att
join attachment_to_note atn with atn . attachment_id = att . id
where atn . note_id = : note_id
EOF ,
2021-10-21 13:49:41 +01:00
[ 'note_id' => $this -> id ],
);
2020-08-28 21:16:26 +01:00
});
}
2021-11-17 17:14:15 +00:00
public function getAttachmentsWithTitle () : array
{
2022-01-03 20:31:39 +00:00
return Cache :: getList ( self :: cacheKeys ( $this -> getId ())[ 'attachments-title' ], function () {
2021-11-17 17:14:15 +00:00
$from_db = DB :: dql (
<<< 'EOF'
select att , atn . title
from attachment att
join attachment_to_note atn with atn . attachment_id = att . id
where atn . note_id = : note_id
EOF ,
[ 'note_id' => $this -> id ],
);
$results = [];
foreach ( $from_db as $fd ) {
$results [] = [ $fd [ 0 ], $fd [ 'title' ]];
}
return $results ;
});
}
2021-08-14 15:07:51 +01:00
public function getLinks () : array
{
2022-01-03 20:31:39 +00:00
return Cache :: getList ( self :: cacheKeys ( $this -> getId ())[ 'links' ], function () {
2021-08-14 15:07:51 +01:00
return DB :: dql (
2021-11-09 23:37:46 +00:00
<<< 'EOF'
select l from link l
join note_to_link ntl with ntl . link_id = l . id
where ntl . note_id = : note_id
EOF ,
2021-10-21 13:49:41 +01:00
[ 'note_id' => $this -> id ],
2021-08-14 15:07:51 +01:00
);
});
}
2021-12-24 21:02:02 +00:00
public function getTags () : array
{
2022-01-03 20:31:39 +00:00
return Cache :: getList ( self :: cacheKeys ( $this -> getId ())[ 'tags' ], fn () => DB :: findBy ( 'note_tag' , [ 'note_id' => $this -> getId ()]));
2021-12-24 21:02:02 +00:00
}
2021-12-10 23:09:39 +00:00
/**
* Returns this Note ' s reply_to / parent .
*
* If we don ' t know the reply , we might know the ** Conversation **!
* This will happen if a known remote user replies to an
* unknown remote user - within a known Conversation .
*
* As such , ** do not take for granted ** that this is a root
* Note of a Conversation , in case this returns null !
* Whenever a note is created , checks should be made
* to guarantee that the latest info is correct .
*/
2021-12-16 11:14:34 +00:00
public function getReplyToNote () : ? self
2021-12-08 22:46:00 +00:00
{
2021-12-26 06:50:36 +00:00
return is_null ( $this -> getReplyTo ()) ? null : self :: getById ( $this -> getReplyTo ());
2021-12-08 22:46:00 +00:00
}
2021-12-10 23:09:39 +00:00
/**
* Returns all ** known ** replies made to this entity
*/
public function getReplies () : array
2021-12-08 22:46:00 +00:00
{
2022-01-03 20:31:39 +00:00
return Cache :: getList ( self :: cacheKeys ( $this -> getId ())[ 'replies' ], fn () => DB :: findBy ( 'note' , [ 'reply_to' => $this -> getId ()], order_by : [ 'created' => 'DESC' , 'id' => 'DESC' ]));
2021-12-08 22:46:00 +00:00
}
2020-11-06 19:47:15 +00:00
/**
* Whether this note is visible to the given actor
*/
2021-12-26 19:50:21 +00:00
public function isVisibleTo ( null | Actor | LocalUser $actor ) : bool
{
// TODO: cache this
switch ( $this -> getScope ()) {
case VisibilityScope :: LOCAL : // The controller handles it if private
case VisibilityScope :: EVERYWHERE :
return true ;
case VisibilityScope :: ADDRESSEE :
// If the actor is logged in and
if ( ! \is_null ( $actor )
&& (
// Is either the author Or
$this -> getActorId () == $actor -> getId ()
// one of the targets
|| \in_array ( $actor -> getId (), $this -> getNotificationTargetIds ())
)) {
return true ;
}
return false ;
case VisibilityScope :: GROUP :
// Only for the group to see
2021-12-27 02:47:04 +00:00
return ! \is_null ( $actor ) && DB :: dql (
2021-12-26 19:50:21 +00:00
<<< 'EOF'
2021-11-24 15:51:01 +00:00
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 . actor_id = : actor_id
EOF ,
2021-12-26 19:50:21 +00:00
[ 'note_id' => $this -> id , 'actor_id' => $actor -> getId ()],
) !== [];
case VisibilityScope :: COLLECTION :
case VisibilityScope :: MESSAGE :
// Only for the collection to see
2021-12-27 02:47:04 +00:00
return ! \is_null ( $actor ) && in_array ( $actor -> getId (), $this -> getNotificationTargetIds ());
2021-12-26 19:50:21 +00:00
default :
2021-12-26 22:17:26 +00:00
Log :: error ( " Unknown scope found: { $this -> getScope () -> value } . " );
2021-12-26 19:50:21 +00:00
}
return false ;
2020-09-10 23:27:23 +01:00
}
2021-12-21 12:24:23 +00:00
/**
2021-12-21 16:04:50 +00:00
* @ return array of ids of Actors
2021-12-21 12:24:23 +00:00
*/
2021-12-25 17:46:45 +00:00
private array $object_mentions_ids = [];
public function setObjectMentionsIds ( array $mentions ) : self
{
$this -> object_mentions_ids = $mentions ;
return $this ;
}
2022-01-02 22:02:25 +00:00
/**
* @ see Entity -> getNotificationTargetIds
*/
2021-12-26 06:50:36 +00:00
public function getNotificationTargetIds ( array $ids_already_known = [], ? int $sender_id = null , bool $include_additional = true ) : array
2021-12-21 16:04:50 +00:00
{
2021-12-25 17:46:45 +00:00
$target_ids = $this -> object_mentions_ids ? ? [];
if ( $target_ids === []) {
2022-01-17 20:45:47 +00:00
$content = $this -> getContent ();
2021-12-25 17:46:45 +00:00
if ( ! \array_key_exists ( 'object' , $ids_already_known )) {
2022-01-17 20:45:47 +00:00
if ( ! \is_null ( $content )) {
$mentions = Formatting :: findMentions ( $content , $this -> getActor ());
foreach ( $mentions as $mention ) {
foreach ( $mention [ 'mentioned' ] as $m ) {
$target_ids [] = $m -> getId ();
}
2021-12-25 17:46:45 +00:00
}
2021-12-21 16:04:50 +00:00
}
2021-12-25 17:46:45 +00:00
} else {
$target_ids = $ids_already_known [ 'object' ];
2021-12-21 16:04:50 +00:00
}
}
2021-12-26 06:50:36 +00:00
if ( ! \array_key_exists ( 'object-related' , $ids_already_known )) {
if ( ! is_null ( $parent = $this -> getReplyToNote ())) {
2021-12-27 03:24:26 +00:00
$target_ids [] = $parent -> getActorId ();
2021-12-26 06:50:36 +00:00
array_push ( $target_ids , ... $parent -> getNotificationTargetIds ());
}
} else {
array_push ( $target_ids , ... $ids_already_known [ 'object-related' ]);
}
2021-12-21 16:04:50 +00:00
// Additional actors that should know about this
2021-12-26 06:50:36 +00:00
if ( $include_additional && \array_key_exists ( 'additional' , $ids_already_known )) {
2021-12-21 16:04:50 +00:00
array_push ( $target_ids , ... $ids_already_known [ 'additional' ]);
}
return array_unique ( $target_ids );
}
/**
* @ return array of Actors
*/
2021-12-26 06:50:36 +00:00
public function getNotificationTargets ( array $ids_already_known = [], ? int $sender_id = null , bool $include_additional = true ) : array
2021-12-21 16:04:50 +00:00
{
2021-12-26 06:50:36 +00:00
if ( $include_additional && \array_key_exists ( 'additional' , $ids_already_known )) {
2021-12-21 16:04:50 +00:00
$target_ids = $this -> getNotificationTargetIds ( $ids_already_known , $sender_id );
return $target_ids === [] ? [] : DB :: findBy ( 'actor' , [ 'id' => $target_ids ]);
}
2021-11-27 04:12:44 +00:00
$mentioned = [];
2021-12-23 13:27:31 +00:00
if ( ! \array_key_exists ( 'object' , $ids_already_known )) {
2021-12-21 16:04:50 +00:00
$mentions = Formatting :: findMentions ( $this -> getContent (), $this -> getActor ());
foreach ( $mentions as $mention ) {
foreach ( $mention [ 'mentioned' ] as $m ) {
$mentioned [] = $m ;
}
2021-11-27 04:12:44 +00:00
}
2021-12-21 16:04:50 +00:00
} else {
$mentioned = $ids_already_known [ 'object' ] === [] ? [] : DB :: findBy ( 'actor' , [ 'id' => $ids_already_known [ 'object' ]]);
2021-11-27 04:12:44 +00:00
}
2021-12-21 16:04:50 +00:00
2021-12-26 06:50:36 +00:00
if ( ! \array_key_exists ( 'object-related' , $ids_already_known )) {
if ( ! is_null ( $parent = $this -> getReplyToNote ())) {
2021-12-27 03:24:26 +00:00
$mentioned [] = $parent -> getActor ();
2021-12-26 06:50:36 +00:00
array_push ( $mentioned , ... $parent -> getNotificationTargets ());
}
} else {
array_push ( $mentioned , ... $ids_already_known [ 'object-related' ]);
}
2021-11-27 04:12:44 +00:00
return $mentioned ;
}
2021-12-28 06:18:59 +00:00
public function delete ( ? Actor $actor = null , string $source = 'web' ) : Activity
2021-12-10 02:35:28 +00:00
{
2021-12-28 06:18:59 +00:00
Event :: handle ( 'NoteDeleteRelated' , [ & $this , $actor ]);
DB :: persist ( $activity = Activity :: create ([
'actor_id' => $actor -> getId (),
'verb' => 'delete' ,
'object_type' => 'note' ,
'object_id' => $this -> getId (),
'source' => $source ,
]));
DB :: remove ( DB :: findOneBy ( self :: class , [ 'id' => $this -> id ]));
return $activity ;
2021-12-10 02:35:28 +00:00
}
2022-01-03 20:31:39 +00:00
public static function ensureCanInteract ( ? Note $note , LocalUser | Actor $actor ) : Note
{
if ( \is_null ( $note )) {
throw new NoSuchNoteException ();
} elseif ( ! $note -> isVisibleTo ( $actor )) {
throw new ClientException ( _m ( 'You don\'t have permissions to view this note.' ), 401 );
} else {
return $note ;
}
}
2020-03-29 20:56:35 +01:00
public static function schemaDef () : array
{
2020-08-15 06:47:45 +01:00
return [
2020-08-13 00:57:22 +01:00
'name' => 'note' ,
2020-03-29 20:56:35 +01:00
'fields' => [
2021-12-10 23:09:39 +00:00
'id' => [ 'type' => 'serial' , 'not null' => true ],
'actor_id' => [ 'type' => 'int' , 'foreign key' => true , 'target' => 'Actor.id' , 'multiplicity' => 'one to one' , 'not null' => true , 'description' => 'who made the note' ],
'content' => [ 'type' => 'text' , 'description' => 'note content' ],
'content_type' => [ 'type' => 'varchar' , 'not null' => true , 'default' => 'text/plain' , 'length' => 129 , 'description' => 'A note can be written in a multitude of formats such as text/plain, text/markdown, application/x-latex, and text/html' ],
'rendered' => [ 'type' => 'text' , 'description' => 'rendered note content, so we can keep the microtags (if not local)' ],
'conversation_id' => [ 'type' => 'serial' , 'not null' => true , 'foreign key' => true , 'target' => 'Conversation.id' , 'multiplicity' => 'one to one' , 'description' => 'the conversation identifier' ],
2021-12-26 16:51:36 +00:00
'reply_to' => [ 'type' => 'int' , 'not null' => false , 'default' => null , 'foreign key' => true , 'target' => 'Note.id' , 'multiplicity' => 'one to one' , 'description' => 'note replied to, null if root of a conversation' ],
2021-12-10 23:09:39 +00:00
'is_local' => [ 'type' => 'bool' , 'not null' => true , 'description' => 'was this note generated by a local actor' ],
'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-12-26 17:31:53 +00:00
'scope' => [ 'type' => 'int' , 'not null' => true , 'default' => VisibilityScope :: EVERYWHERE -> value , 'description' => 'bit map for distribution scope; 1 = everywhere; 2 = this server only; 4 = addressees; 8 = groups; 16 = collection; 32 = messages' ],
2021-12-10 23:09:39 +00:00
'url' => [ 'type' => 'text' , 'description' => 'Permalink to Note' ],
'language_id' => [ 'type' => 'int' , 'foreign key' => true , 'target' => 'Language.id' , 'multiplicity' => 'one to many' , 'description' => 'The language for this note' ],
'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-29 20:56:35 +01:00
],
2021-02-22 21:34:59 +00:00
'primary key' => [ 'id' ],
'indexes' => [
2021-09-18 03:22:27 +01:00
'note_created_id_is_local_idx' => [ 'created' , 'is_local' ],
'note_actor_created_idx' => [ 'actor_id' , 'created' ],
'note_is_local_created_actor_idx' => [ 'is_local' , 'created' , 'actor_id' ],
2021-12-08 22:46:00 +00:00
'note_reply_to_idx' => [ 'reply_to' ],
2020-03-29 20:56:35 +01:00
],
2021-10-28 01:26:16 +01:00
'fulltext indexes' => [ 'notice_fulltext_idx' => [ 'content' ]], // TODO make this configurable
2020-03-29 20:56:35 +01:00
];
}
}