Commit 0c187ef7 authored by Yassine Doghri's avatar Yassine Doghri
Browse files

feat(comments): add like / undo like to comment + add comment page

parent bb4752c3
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -771,12 +771,24 @@ $routes->group('@(:podcastHandle)', function ($routes): void {
                'controller-method' => 'EpisodeController::comments/$1/$2',
            ],
        ]);
        $routes->get('comments/(:uuid)', 'EpisodeController::comment/$1/$2/$3', [
        $routes->get('comments/(:uuid)', 'EpisodeCommentController::view/$1/$2/$3', [
            'as' => 'comment',
            'application/activity+json' => [
                'controller-method' => 'EpisodeController::commentObject/$1/$2',
            ],
            'application/podcast-activity+json' => [
                'controller-method' => 'EpisodeController::commentObject/$1/$2',
            ],
            'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [
                'controller-method' => 'EpisodeController::commentObject/$1/$2',
            ],
        ]);
        $routes->get('comments/(:uuid)/replies', 'EpisodeController::commentReplies/$1/$2/$3', [
        $routes->get('comments/(:uuid)/replies', 'EpisodeCommentController::replies/$1/$2/$3', [
            'as' => 'comment-replies',
        ]);
        $routes->post('comments/(:uuid)/like', 'EpisodeCommentController::attemptLike/$1/$2/$3', [
            'as' => 'comment-attempt-like',
        ]);
        $routes->get('oembed.json', 'EpisodeController::oembedJSON/$1/$2', [
            'as' => 'episode-oembed-json',
        ]);
+4 −4
Original line number Diff line number Diff line
@@ -10,13 +10,13 @@ declare(strict_types=1);

namespace App\Controllers\Admin;

use App\Entities\Comment;
use App\Entities\Episode;
use App\Entities\EpisodeComment;
use App\Entities\Image;
use App\Entities\Location;
use App\Entities\Podcast;
use App\Entities\Post;
use App\Models\CommentModel;
use App\Models\EpisodeCommentModel;
use App\Models\EpisodeModel;
use App\Models\PodcastModel;
use App\Models\PostModel;
@@ -800,7 +800,7 @@ class EpisodeController extends BaseController

        $message = $this->request->getPost('message');

        $newComment = new Comment([
        $newComment = new EpisodeComment([
            'actor_id' => interact_as_actor_id(),
            'episode_id' => $this->episode->id,
            'message' => $message,
@@ -808,7 +808,7 @@ class EpisodeController extends BaseController
            'created_by' => user_id(),
        ]);

        $commentModel = new CommentModel();
        $commentModel = new EpisodeCommentModel();
        if (
            ! $commentModel->addComment($newComment, true)
        ) {
+173 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

/**
 * @copyright  2020 Podlibre
 * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
 * @link       https://castopod.org/
 */

namespace App\Controllers;

use ActivityPub\Entities\Actor;
use ActivityPub\Objects\OrderedCollectionObject;
use ActivityPub\Objects\OrderedCollectionPage;
use Analytics\AnalyticsTrait;
use App\Controllers\Admin\BaseController;
use App\Entities\Episode;
use App\Entities\EpisodeComment;
use App\Entities\Podcast;
use App\Libraries\CommentObject;
use App\Models\EpisodeCommentModel;
use App\Models\EpisodeModel;
use App\Models\PodcastModel;
use CodeIgniter\Exceptions\PageNotFoundException;
use CodeIgniter\HTTP\RedirectResponse;
use CodeIgniter\HTTP\Response;

class EpisodeCommentController extends BaseController
{
    use AnalyticsTrait;

    protected Podcast $podcast;

    protected Actor $actor;

    protected Episode $episode;

    protected EpisodeComment $comment;

    public function _remap(string $method, string ...$params): mixed
    {
        if (count($params) < 3) {
            throw PageNotFoundException::forPageNotFound();
        }

        if (
            ($podcast = (new PodcastModel())->getPodcastByHandle($params[0])) === null
        ) {
            throw PageNotFoundException::forPageNotFound();
        }

        $this->podcast = $podcast;
        $this->actor = $podcast->actor;

        if (
            ($episode = (new EpisodeModel())->getEpisodeBySlug($params[0], $params[1])) === null
            ) {
            throw PageNotFoundException::forPageNotFound();
        }

        $this->episode = $episode;

        if (
            ($comment = (new EpisodeCommentModel())->getCommentById($params[2])) === null
        ) {
            throw PageNotFoundException::forPageNotFound();
        }

        $this->comment = $comment;

        unset($params[2]);
        unset($params[1]);
        unset($params[0]);

        return $this->{$method}(...$params);
    }

    public function view(): string
    {
        // Prevent analytics hit when authenticated
        if (! can_user_interact()) {
            $this->registerPodcastWebpageHit($this->podcast->id);
        }

        $cacheName = implode(
            '_',
            array_filter([
                'page',
                "comment#{$this->comment->id}",
                service('request')
                    ->getLocale(),
                can_user_interact() ? '_authenticated' : null,
            ]),
        );

        if (! ($cachedView = cache($cacheName))) {
            $data = [
                'podcast' => $this->podcast,
                'actor' => $this->actor,
                'episode' => $this->episode,
                'comment' => $this->comment,
            ];

            // if user is logged in then send to the authenticated activity view
            if (can_user_interact()) {
                helper('form');
                return view('podcast/comment_authenticated', $data);
            }
            return view('podcast/comment', $data, [
                'cache' => DECADE,
                'cache_name' => $cacheName,
            ]);
        }

        return $cachedView;
    }

    /**
     * @noRector ReturnTypeDeclarationRector
     */
    public function commentObject(): Response
    {
        $commentObject = new CommentObject($this->comment);

        return $this->response
            ->setContentType('application/json')
            ->setBody($commentObject->toJSON());
    }

    public function replies(): Response
    {
        /**
         * get comment replies
         */
        $commentReplies = model('CommentModel', false)
            ->where('in_reply_to_id', service('uuid')->fromString($this->comment->id)->getBytes())
            ->orderBy('created_at', 'ASC');

        $pageNumber = (int) $this->request->getGet('page');

        if ($pageNumber < 1) {
            $commentReplies->paginate(12);
            $pager = $commentReplies->pager;
            $collection = new OrderedCollectionObject(null, $pager);
        } else {
            $paginatedReplies = $commentReplies->paginate(12, 'default', $pageNumber);
            $pager = $commentReplies->pager;

            $orderedItems = [];
            if ($paginatedReplies !== null) {
                foreach ($paginatedReplies as $reply) {
                    $replyObject = new CommentObject($reply);
                    $orderedItems[] = $replyObject;
                }
            }

            $collection = new OrderedCollectionPage($pager, $orderedItems);
        }

        return $this->response
            ->setContentType('application/activity+json')
            ->setBody($collection->toJSON());
    }

    public function attemptLike(): RedirectResponse
    {
        model('LikeModel')
            ->toggleLike(interact_as_actor(), $this->comment);

        return redirect()->back();
    }
}
+0 −55
Original line number Diff line number Diff line
@@ -15,10 +15,8 @@ use ActivityPub\Objects\OrderedCollectionPage;
use Analytics\AnalyticsTrait;
use App\Entities\Episode;
use App\Entities\Podcast;
use App\Libraries\CommentObject;
use App\Libraries\NoteObject;
use App\Libraries\PodcastEpisode;
use App\Models\CommentModel;
use App\Models\EpisodeModel;
use App\Models\PodcastModel;
use CodeIgniter\Database\BaseBuilder;
@@ -256,57 +254,4 @@ class EpisodeController extends BaseController
            ->setHeader('Access-Control-Allow-Origin', '*')
            ->setBody($collection->toJSON());
    }

    /**
     * @noRector ReturnTypeDeclarationRector
     */
    public function comment(string $commentId): Response
    {
        if (
            ($comment = (new CommentModel())->getCommentById($commentId)) === null
        ) {
            throw PageNotFoundException::forPageNotFound();
        }

        $commentObject = new CommentObject($comment);

        return $this->response
            ->setContentType('application/json')
            ->setBody($commentObject->toJSON());
    }

    public function commentReplies(string $commentId): Response
    {
        /**
         * get comment replies
         */
        $commentReplies = model('CommentModel', false)
            ->where('in_reply_to_id', service('uuid')->fromString($commentId)->getBytes())
            ->orderBy('created_at', 'ASC');

        $pageNumber = (int) $this->request->getGet('page');

        if ($pageNumber < 1) {
            $commentReplies->paginate(12);
            $pager = $commentReplies->pager;
            $collection = new OrderedCollectionObject(null, $pager);
        } else {
            $paginatedReplies = $commentReplies->paginate(12, 'default', $pageNumber);
            $pager = $commentReplies->pager;

            $orderedItems = [];
            if ($paginatedReplies !== null) {
                foreach ($paginatedReplies as $reply) {
                    $replyObject = new CommentObject($reply);
                    $orderedItems[] = $replyObject;
                }
            }

            $collection = new OrderedCollectionPage($pager, $orderedItems);
        }

        return $this->response
            ->setContentType('application/activity+json')
            ->setBody($collection->toJSON());
    }
}
+7 −13
Original line number Diff line number Diff line
@@ -3,9 +3,9 @@
declare(strict_types=1);

/**
 * Class AddComments creates comments table in database
 * Class AddEpisodeComments creates episode_comments table in database
 *
 * @copyright  2020 Podlibre
 * @copyright  2021 Podlibre
 * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
 * @link       https://castopod.org/
 */
@@ -14,7 +14,7 @@ namespace App\Database\Migrations;

use CodeIgniter\Database\Migration;

class AddComments extends Migration
class AddEpisodeComments extends Migration
{
    public function up(): void
    {
@@ -42,22 +42,16 @@ class AddComments extends Migration
            ],
            'message' => [
                'type' => 'VARCHAR',
                'constraint' => 500,
                'null' => true,
                'constraint' => 5000,
            ],
            'message_html' => [
                'type' => 'VARCHAR',
                'constraint' => 600,
                'null' => true,
                'constraint' => 6000,
            ],
            'likes_count' => [
                'type' => 'INT',
                'unsigned' => true,
            ],
            'dislikes_count' => [
                'type' => 'INT',
                'unsigned' => true,
            ],
            'replies_count' => [
                'type' => 'INT',
                'unsigned' => true,
@@ -75,11 +69,11 @@ class AddComments extends Migration
        $this->forge->addForeignKey('episode_id', 'episodes', 'id', '', 'CASCADE');
        $this->forge->addForeignKey('actor_id', 'activitypub_actors', 'id', '', 'CASCADE');
        $this->forge->addForeignKey('created_by', 'users', 'id');
        $this->forge->createTable('comments');
        $this->forge->createTable('episode_comments');
    }

    public function down(): void
    {
        $this->forge->dropTable('comments');
        $this->forge->dropTable('episode_comments');
    }
}
Loading