[COMPONENTS][Conversation] Conversation entity moved to respective component, URI column added
Route for conversation added and Conversation Controller created. [CONTROLLER][Conversation] Created ConversationShow function, will be used to render the conversation route page [ENTITY][Note] Conversation id column added, this way a Note can have a direct relation with its respective conversation.
This commit is contained in:
parent
c494928b46
commit
c83ae76a68
|
@ -26,6 +26,7 @@ declare(strict_types = 1);
|
||||||
|
|
||||||
namespace Component\Conversation\Controller;
|
namespace Component\Conversation\Controller;
|
||||||
|
|
||||||
|
use _PHPStan_76800bfb5\Nette\NotImplementedException;
|
||||||
use App\Core\Controller\FeedController;
|
use App\Core\Controller\FeedController;
|
||||||
use App\Core\DB\DB;
|
use App\Core\DB\DB;
|
||||||
use App\Core\Form;
|
use App\Core\Form;
|
||||||
|
@ -55,6 +56,7 @@ class Conversation extends FeedController
|
||||||
// if note is a reply -> link from above plus anchor
|
// if note is a reply -> link from above plus anchor
|
||||||
public function ConversationShow(Request $request)
|
public function ConversationShow(Request $request)
|
||||||
{
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
$actor_id = Common::ensureLoggedIn()->getId();
|
$actor_id = Common::ensureLoggedIn()->getId();
|
||||||
$notes = DB::dql('select n from App\Entity\Note n '
|
$notes = DB::dql('select n from App\Entity\Note n '
|
||||||
. 'where n.reply_to is not null and n.actor_id = :id '
|
. 'where n.reply_to is not null and n.actor_id = :id '
|
||||||
|
|
|
@ -40,7 +40,6 @@ use App\Util\Exception\DuplicateFoundException;
|
||||||
use App\Util\Exception\InvalidFormException;
|
use App\Util\Exception\InvalidFormException;
|
||||||
use App\Util\Exception\NoLoggedInUser;
|
use App\Util\Exception\NoLoggedInUser;
|
||||||
use App\Util\Exception\NoSuchNoteException;
|
use App\Util\Exception\NoSuchNoteException;
|
||||||
use App\Util\Exception\NotImplementedException;
|
|
||||||
use App\Util\Exception\RedirectException;
|
use App\Util\Exception\RedirectException;
|
||||||
use App\Util\Exception\ServerException;
|
use App\Util\Exception\ServerException;
|
||||||
use App\Util\Form\FormFields;
|
use App\Util\Form\FormFields;
|
||||||
|
@ -143,20 +142,15 @@ class Reply extends FeedController
|
||||||
|
|
||||||
public function replies(Request $request)
|
public function replies(Request $request)
|
||||||
{
|
{
|
||||||
// TODO replies
|
|
||||||
throw new NotImplementedException;
|
|
||||||
$actor_id = Common::ensureLoggedIn()->getId();
|
$actor_id = Common::ensureLoggedIn()->getId();
|
||||||
$notes = DB::dql('select n from App\Entity\Note n '
|
$notes = DB::dql('select n from App\Entity\Note n '
|
||||||
. 'where n.reply_to is not null and n.actor_id = :id '
|
. 'where n.reply_to is not null and n.actor_id = :id '
|
||||||
. 'order by n.created DESC', ['id' => $actor_id], );
|
. 'order by n.created DESC', ['id' => $actor_id], );
|
||||||
|
return [
|
||||||
$notes_out = null;
|
|
||||||
Event::handle('FormatNoteList', [$notes, &$notes_out]);
|
|
||||||
|
|
||||||
return $this->process_feed([
|
|
||||||
'_template' => 'feeds/feed.html.twig',
|
'_template' => 'feeds/feed.html.twig',
|
||||||
'notes' => $notes_out,
|
'notes' => $notes,
|
||||||
|
'should_format' => false,
|
||||||
'page_title' => 'Replies feed',
|
'page_title' => 'Replies feed',
|
||||||
]);
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,6 +132,7 @@ class Conversation extends Component
|
||||||
{
|
{
|
||||||
$r->connect('reply_add', '/object/note/{id<\d+>}/reply', [ReplyController::class, 'replyAddNote']);
|
$r->connect('reply_add', '/object/note/{id<\d+>}/reply', [ReplyController::class, 'replyAddNote']);
|
||||||
$r->connect('replies', '/@{nickname<' . Nickname::DISPLAY_FMT . '>}/replies', [ReplyController::class, 'replies']);
|
$r->connect('replies', '/@{nickname<' . Nickname::DISPLAY_FMT . '>}/replies', [ReplyController::class, 'replies']);
|
||||||
|
$r->connect('conversation', '/conversation/{id<\d+>}', [ReplyController::class, 'conversation']);
|
||||||
|
|
||||||
return Event::next;
|
return Event::next;
|
||||||
}
|
}
|
||||||
|
|
108
components/Conversation/Entity/Conversation.php
Normal file
108
components/Conversation/Entity/Conversation.php
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
// {{{ License
|
||||||
|
|
||||||
|
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||||
|
//
|
||||||
|
// GNU social is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
namespace Component\Conversation\Entity;
|
||||||
|
|
||||||
|
use App\Core\DB\DB;
|
||||||
|
use App\Core\Entity;
|
||||||
|
use App\Entity\Note;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity class for Conversations
|
||||||
|
*
|
||||||
|
* @category DB
|
||||||
|
* @package GNUsocial
|
||||||
|
*
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||||
|
* @copyright 2010 StatusNet Inc.
|
||||||
|
* @copyright 2009-2014 Free Software Foundation, Inc http://www.fsf.org
|
||||||
|
* @author Hugo Sales <hugo@hsal.es>
|
||||||
|
* @author Eliseu Amaro <mail@eliseuama.ro>
|
||||||
|
* @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org
|
||||||
|
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||||
|
*/
|
||||||
|
class Conversation extends Entity
|
||||||
|
{
|
||||||
|
// {{{ Autocode
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
private int $id;
|
||||||
|
private string $uri; // varchar(191) unique_key not 255 because utf8mb4 takes more space
|
||||||
|
private int $note_id;
|
||||||
|
|
||||||
|
public function setId(int $id): self
|
||||||
|
{
|
||||||
|
$this->id = $id;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId(): int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUri(string $uri): self
|
||||||
|
{
|
||||||
|
$this->uri = $uri;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUri(): string
|
||||||
|
{
|
||||||
|
return $this->uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setNoteId(int $note_id): self
|
||||||
|
{
|
||||||
|
$this->note_id = $note_id;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNoteId(): int
|
||||||
|
{
|
||||||
|
return $this->note_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
// }}} Autocode
|
||||||
|
|
||||||
|
public static function schemaDef(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'conversation',
|
||||||
|
'fields' => [
|
||||||
|
'id' => ['type' => 'serial', 'not null' => true, 'description' => 'Serial identifier, since any additional meaning would require updating its value for every reply upon receiving a new aparent root'],
|
||||||
|
'uri' => ['type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'URI of the conversation'],
|
||||||
|
'note_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Note.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'Root of note for this conversation'],
|
||||||
|
],
|
||||||
|
'primary key' => ['id'],
|
||||||
|
'unique keys' => [
|
||||||
|
'conversation_uri_uniq' => ['uri'],
|
||||||
|
],
|
||||||
|
'foreign keys' => [
|
||||||
|
'note_id_to_id_fkey' => ['note', ['note_id' => 'id']],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,17 +48,18 @@ class Note extends Entity
|
||||||
// @codeCoverageIgnoreStart
|
// @codeCoverageIgnoreStart
|
||||||
private int $id;
|
private int $id;
|
||||||
private int $actor_id;
|
private int $actor_id;
|
||||||
private ?string $content_type = null;
|
private ?string $content;
|
||||||
private ?string $content = null;
|
private string $content_type = 'text/plain';
|
||||||
private ?string $rendered = null;
|
private ?string $rendered;
|
||||||
|
private int $conversation_id;
|
||||||
private ?int $reply_to;
|
private ?int $reply_to;
|
||||||
private bool $is_local;
|
private bool $is_local;
|
||||||
private ?string $source;
|
private ?string $source;
|
||||||
private int $scope = VisibilityScope::PUBLIC;
|
private int $scope = 1;
|
||||||
private string $url;
|
private ?string $url;
|
||||||
private ?int $language_id = null;
|
private ?int $language_id;
|
||||||
private DateTimeInterface $created;
|
private \DateTimeInterface $created;
|
||||||
private DateTimeInterface $modified;
|
private \DateTimeInterface $modified;
|
||||||
|
|
||||||
public function setId(int $id): self
|
public function setId(int $id): self
|
||||||
{
|
{
|
||||||
|
@ -82,17 +83,6 @@ class Note extends Entity
|
||||||
return $this->actor_id;
|
return $this->actor_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getContentType(): string
|
|
||||||
{
|
|
||||||
return $this->content_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setContentType(string $content_type): self
|
|
||||||
{
|
|
||||||
$this->content_type = $content_type;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setContent(?string $content): self
|
public function setContent(?string $content): self
|
||||||
{
|
{
|
||||||
$this->content = $content;
|
$this->content = $content;
|
||||||
|
@ -104,6 +94,17 @@ class Note extends Entity
|
||||||
return $this->content;
|
return $this->content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setContentType(string $content_type): self
|
||||||
|
{
|
||||||
|
$this->content_type = $content_type;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContentType(): string
|
||||||
|
{
|
||||||
|
return $this->content_type;
|
||||||
|
}
|
||||||
|
|
||||||
public function setRendered(?string $rendered): self
|
public function setRendered(?string $rendered): self
|
||||||
{
|
{
|
||||||
$this->rendered = $rendered;
|
$this->rendered = $rendered;
|
||||||
|
@ -115,6 +116,17 @@ class Note extends Entity
|
||||||
return $this->rendered;
|
return $this->rendered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setConversationId(int $conversation_id): self
|
||||||
|
{
|
||||||
|
$this->conversation_id = $conversation_id;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConversationId(): int
|
||||||
|
{
|
||||||
|
return $this->conversation_id;
|
||||||
|
}
|
||||||
|
|
||||||
public function setReplyTo(?int $reply_to): self
|
public function setReplyTo(?int $reply_to): self
|
||||||
{
|
{
|
||||||
$this->reply_to = $reply_to;
|
$this->reply_to = $reply_to;
|
||||||
|
@ -123,7 +135,7 @@ class Note extends Entity
|
||||||
|
|
||||||
public function getReplyTo(): ?int
|
public function getReplyTo(): ?int
|
||||||
{
|
{
|
||||||
return $this->reply_to ?: null;
|
return $this->reply_to;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setIsLocal(bool $is_local): self
|
public function setIsLocal(bool $is_local): self
|
||||||
|
@ -159,20 +171,15 @@ class Note extends Entity
|
||||||
return $this->scope;
|
return $this->scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUrl(): string
|
public function setUrl(?string $url): self
|
||||||
{
|
|
||||||
return $this->url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setUrl(string $url): self
|
|
||||||
{
|
{
|
||||||
$this->url = $url;
|
$this->url = $url;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLanguageId(): ?int
|
public function getUrl(): ?string
|
||||||
{
|
{
|
||||||
return $this->language_id;
|
return $this->url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setLanguageId(?int $language_id): self
|
public function setLanguageId(?int $language_id): self
|
||||||
|
@ -181,28 +188,34 @@ class Note extends Entity
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setCreated(DateTimeInterface $created): self
|
public function getLanguageId(): ?int
|
||||||
|
{
|
||||||
|
return $this->language_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCreated(\DateTimeInterface $created): self
|
||||||
{
|
{
|
||||||
$this->created = $created;
|
$this->created = $created;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreated(): DateTimeInterface
|
public function getCreated(): \DateTimeInterface
|
||||||
{
|
{
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setModified(DateTimeInterface $modified): self
|
public function setModified(\DateTimeInterface $modified): self
|
||||||
{
|
{
|
||||||
$this->modified = $modified;
|
$this->modified = $modified;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getModified(): DateTimeInterface
|
public function getModified(): \DateTimeInterface
|
||||||
{
|
{
|
||||||
return $this->modified;
|
return $this->modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
// }}} Autocode
|
// }}} Autocode
|
||||||
|
|
||||||
|
@ -420,19 +433,20 @@ class Note extends Entity
|
||||||
return [
|
return [
|
||||||
'name' => 'note',
|
'name' => 'note',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'id' => ['type' => 'serial', 'not null' => true],
|
'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'],
|
'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' => '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'],
|
'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)'],
|
'rendered' => ['type' => 'text', 'description' => 'rendered note content, so we can keep the microtags (if not local)'],
|
||||||
'reply_to' => ['type' => 'int', 'foreign key' => true, 'target' => 'Note.id', 'multiplicity' => 'one to one', 'description' => 'note replied to, null if root of a conversation'],
|
'conversation_id' => ['type' => 'serial', 'not null' => true, 'foreign key' => true, 'target' => 'Conversation.id', 'multiplicity' => 'one to one', 'description' => 'the conversation identifier'],
|
||||||
'is_local' => ['type' => 'bool', 'not null' => true, 'description' => 'was this note generated by a local actor'],
|
'reply_to' => ['type' => 'int', 'foreign key' => true, 'target' => 'Note.id', 'multiplicity' => 'one to one', 'description' => 'note replied to, null if root of a conversation'],
|
||||||
'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"'],
|
'is_local' => ['type' => 'bool', 'not null' => true, 'description' => 'was this note generated by a local actor'],
|
||||||
'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 = subscribers; 16 = messages; null = default'],
|
'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"'],
|
||||||
'url' => ['type' => 'text', 'description' => 'Permalink to Note'],
|
'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 = subscribers; 16 = messages; null = default'],
|
||||||
'language_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Language.id', 'multiplicity' => 'one to many', 'description' => 'The language for this note'],
|
'url' => ['type' => 'text', 'description' => 'Permalink to Note'],
|
||||||
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],
|
'language_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Language.id', 'multiplicity' => 'one to many', 'description' => 'The language for this note'],
|
||||||
'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'],
|
'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'],
|
||||||
],
|
],
|
||||||
'primary key' => ['id'],
|
'primary key' => ['id'],
|
||||||
'indexes' => [
|
'indexes' => [
|
||||||
|
|
Loading…
Reference in New Issue
Block a user