Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions assets/styles/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,6 @@
@use 'themes/solarized';
@use 'themes/tokyo-night';
@use 'components/tag';
@use 'widgets/boosted_by';

@import 'glightbox/dist/css/glightbox.min.css';
5 changes: 5 additions & 0 deletions assets/styles/widgets/boosted_by.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.boosted-by {
font-size: 0.8rem;
max-height: 2lh;
overflow: hidden;
}
57 changes: 37 additions & 20 deletions src/Controller/Api/Combined/CombinedRetrieveApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use App\Controller\Api\BaseApi;
use App\Controller\Traits\PrivateContentTrait;
use App\DTO\ContentBoostResponseDto;
use App\DTO\ContentResponseDto;
use App\Entity\Entry;
use App\Entity\EntryComment;
Expand Down Expand Up @@ -811,19 +812,7 @@ private function serializeContent(PagerfantaInterface $content, array $headers):
{
$result = [];
foreach ($content as $item) {
if ($item instanceof Entry) {
$this->handlePrivateContent($item);
$result[] = new ContentResponseDto(entry: $this->serializeEntry($this->entryFactory->createDto($item), $this->tagLinkRepository->getTagsOfContent($item)));
} elseif ($item instanceof Post) {
$this->handlePrivateContent($item);
$result[] = new ContentResponseDto(post: $this->serializePost($this->postFactory->createDto($item), $this->tagLinkRepository->getTagsOfContent($item)));
} elseif ($item instanceof EntryComment) {
$this->handlePrivateContent($item);
$result[] = new ContentResponseDto(entryComment: $this->serializeEntryComment($this->entryCommentFactory->createDto($item), $this->tagLinkRepository->getTagsOfContent($item)));
} elseif ($item instanceof PostComment) {
$this->handlePrivateContent($item);
$result[] = new ContentResponseDto(postComment: $this->serializePostComment($this->postCommentFactory->createDto($item), $this->tagLinkRepository->getTagsOfContent($item)));
}
$result[] = $this->createContentResponse($item);
}

return new JsonResponse($this->serializePaginated($result, $content), headers: $headers);
Expand All @@ -833,18 +822,46 @@ private function serializeContentCursored(CursorPaginationInterface $content, ar
{
$result = [];
foreach ($content as $item) {
if ($item instanceof Entry) {
$this->handlePrivateContent($item);
$result[] = new ContentResponseDto(entry: $this->serializeEntry($this->entryFactory->createDto($item), $this->tagLinkRepository->getTagsOfContent($item)));
} elseif ($item instanceof Post) {
$this->handlePrivateContent($item);
$result[] = new ContentResponseDto(post: $this->serializePost($this->postFactory->createDto($item), $this->tagLinkRepository->getTagsOfContent($item)));
}
$result[] = $this->createContentResponse($item);
}

return new JsonResponse($this->serializeCursorPaginated($result, $content), headers: $headers);
}

private function createContentResponse(Entry|EntryComment|Post|PostComment $item): ContentResponseDto
{
$this->handlePrivateContent($item);
$boostedBy = null;
if (isset($item->extendedContentProperties['boostUsers'])) {
$boostedBy = array_map(
fn (array $boost): ContentBoostResponseDto => new ContentBoostResponseDto(
$this->userFactory->createSmallDto($boost['user']),
$boost['time'],
),
$item->extendedContentProperties['boostUsers'],
);
}

return match (true) {
$item instanceof Entry => new ContentResponseDto(
entry: $this->serializeEntry($this->entryFactory->createDto($item), $this->tagLinkRepository->getTagsOfContent($item)),
boostedBy: $boostedBy,
),
$item instanceof Post => new ContentResponseDto(
post: $this->serializePost($this->postFactory->createDto($item), $this->tagLinkRepository->getTagsOfContent($item)),
boostedBy: $boostedBy,
),
$item instanceof EntryComment => new ContentResponseDto(
entryComment: $this->serializeEntryComment($this->entryCommentFactory->createDto($item), $this->tagLinkRepository->getTagsOfContent($item)),
boostedBy: $boostedBy,
),
$item instanceof PostComment => new ContentResponseDto(
postComment: $this->serializePostComment($this->postCommentFactory->createDto($item), $this->tagLinkRepository->getTagsOfContent($item)),
boostedBy: $boostedBy,
),
};
}

private function getCursor(ContentRepository $contentRepository, string $sortOption, ?string $cursor): int|\DateTime|\DateTimeImmutable
{
$initialCursor = $contentRepository->guessInitialCursor($sortOption);
Expand Down
27 changes: 27 additions & 0 deletions src/DTO/ContentBoostResponseDto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace App\DTO;

use Nelmio\ApiDocBundle\Attribute\Model;
use OpenApi\Attributes as OA;

#[OA\Schema()]
class ContentBoostResponseDto implements \JsonSerializable
{
public function __construct(
#[OA\Property(ref: new Model(type: UserSmallResponseDto::class))]
public UserSmallResponseDto $user,
public \DateTimeImmutable $boostedAt,
) {
}

public function jsonSerialize(): mixed
{
return [
'user' => $this->user,
'boostedAt' => $this->boostedAt->format(\DateTimeInterface::ATOM),
];
}
}
4 changes: 4 additions & 0 deletions src/DTO/ContentResponseDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace App\DTO;

use Nelmio\ApiDocBundle\Attribute\Model;
use OpenApi\Attributes as OA;

/**
Expand All @@ -17,6 +18,9 @@ public function __construct(
public ?PostResponseDto $post = null,
public ?EntryCommentResponseDto $entryComment = null,
public ?PostCommentResponseDto $postComment = null,
/** @var ContentBoostResponseDto[]|null */
#[OA\Property(type: 'array', nullable: true, items: new OA\Items(ref: new Model(type: ContentBoostResponseDto::class)))]
public ?array $boostedBy = null,
) {
}
}
6 changes: 6 additions & 0 deletions src/DTO/SettingsDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public function __construct(
public string $MBIN_DOWNVOTES_MODE,
public bool $MBIN_NEW_USERS_NEED_APPROVAL,
public bool $MBIN_USE_FEDERATION_ALLOW_LIST,
public bool $MBIN_FEED_ALLOW_ENTRY_COMMENTS,
public bool $MBIN_FEED_ALLOW_POST_COMMENTS,
) {
}

Expand Down Expand Up @@ -71,6 +73,8 @@ public function mergeIntoDto(SettingsDto $dto): SettingsDto
$dto->MBIN_DOWNVOTES_MODE = $this->MBIN_DOWNVOTES_MODE ?? $dto->MBIN_DOWNVOTES_MODE;
$dto->MBIN_NEW_USERS_NEED_APPROVAL = $this->MBIN_NEW_USERS_NEED_APPROVAL ?? $dto->MBIN_NEW_USERS_NEED_APPROVAL;
$dto->MBIN_USE_FEDERATION_ALLOW_LIST = $this->MBIN_USE_FEDERATION_ALLOW_LIST ?? $dto->MBIN_USE_FEDERATION_ALLOW_LIST;
$dto->MBIN_FEED_ALLOW_ENTRY_COMMENTS = $this->MBIN_FEED_ALLOW_ENTRY_COMMENTS ?? $dto->MBIN_FEED_ALLOW_ENTRY_COMMENTS;
$dto->MBIN_FEED_ALLOW_POST_COMMENTS = $this->MBIN_FEED_ALLOW_POST_COMMENTS ?? $dto->MBIN_FEED_ALLOW_POST_COMMENTS;

return $dto;
}
Expand Down Expand Up @@ -106,6 +110,8 @@ public function jsonSerialize(): mixed
'MBIN_DOWNVOTES_MODE' => $this->MBIN_DOWNVOTES_MODE,
'MBIN_NEW_USERS_NEED_APPROVAL' => $this->MBIN_NEW_USERS_NEED_APPROVAL,
'MBIN_USE_FEDERATION_ALLOW_LIST' => $this->MBIN_USE_FEDERATION_ALLOW_LIST,
'MBIN_FEED_ALLOW_ENTRY_COMMENTS' => $this->MBIN_FEED_ALLOW_ENTRY_COMMENTS,
'MBIN_FEED_ALLOW_POST_COMMENTS' => $this->MBIN_FEED_ALLOW_POST_COMMENTS,
];
}
}
2 changes: 2 additions & 0 deletions src/Entity/Entry.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use App\Entity\Traits\ActivityPubActivityTrait;
use App\Entity\Traits\CreatedAtTrait;
use App\Entity\Traits\EditedAtTrait;
use App\Entity\Traits\ExtendedContentTrait;
use App\Entity\Traits\RankingTrait;
use App\Entity\Traits\VisibilityTrait;
use App\Entity\Traits\VotableTrait;
Expand Down Expand Up @@ -56,6 +57,7 @@ class Entry implements VotableInterface, CommentInterface, DomainInterface, Visi
use CreatedAtTrait {
CreatedAtTrait::__construct as createdAtTraitConstruct;
}
use ExtendedContentTrait;

public const ENTRY_TYPE_ARTICLE = 'article';
public const ENTRY_TYPE_LINK = 'link';
Expand Down
2 changes: 2 additions & 0 deletions src/Entity/EntryComment.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use App\Entity\Traits\ActivityPubActivityTrait;
use App\Entity\Traits\CreatedAtTrait;
use App\Entity\Traits\EditedAtTrait;
use App\Entity\Traits\ExtendedContentTrait;
use App\Entity\Traits\VisibilityTrait;
use App\Entity\Traits\VotableTrait;
use App\Repository\Criteria as MbinCriteria;
Expand Down Expand Up @@ -48,6 +49,7 @@ class EntryComment implements VotableInterface, VisibilityInterface, ReportInter
use CreatedAtTrait {
CreatedAtTrait::__construct as createdAtTraitConstruct;
}
use ExtendedContentTrait;

#[ManyToOne(targetEntity: User::class, inversedBy: 'entryComments')]
#[JoinColumn(nullable: false, onDelete: 'CASCADE')]
Expand Down
2 changes: 2 additions & 0 deletions src/Entity/Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use App\Entity\Traits\ActivityPubActivityTrait;
use App\Entity\Traits\CreatedAtTrait;
use App\Entity\Traits\EditedAtTrait;
use App\Entity\Traits\ExtendedContentTrait;
use App\Entity\Traits\RankingTrait;
use App\Entity\Traits\VisibilityTrait;
use App\Entity\Traits\VotableTrait;
Expand Down Expand Up @@ -52,6 +53,7 @@ class Post implements VotableInterface, CommentInterface, VisibilityInterface, R
use CreatedAtTrait {
CreatedAtTrait::__construct as createdAtTraitConstruct;
}
use ExtendedContentTrait;

#[ManyToOne(targetEntity: User::class, inversedBy: 'posts')]
#[JoinColumn(nullable: false, onDelete: 'CASCADE')]
Expand Down
2 changes: 2 additions & 0 deletions src/Entity/PostComment.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use App\Entity\Traits\ActivityPubActivityTrait;
use App\Entity\Traits\CreatedAtTrait;
use App\Entity\Traits\EditedAtTrait;
use App\Entity\Traits\ExtendedContentTrait;
use App\Entity\Traits\VisibilityTrait;
use App\Entity\Traits\VotableTrait;
use App\Repository\Criteria as MbinCriteria;
Expand Down Expand Up @@ -48,6 +49,7 @@ class PostComment implements VotableInterface, VisibilityInterface, ReportInterf
use CreatedAtTrait {
CreatedAtTrait::__construct as createdAtTraitConstruct;
}
use ExtendedContentTrait;

#[ManyToOne(targetEntity: User::class, inversedBy: 'postComments')]
#[JoinColumn(nullable: false, onDelete: 'CASCADE')]
Expand Down
16 changes: 16 additions & 0 deletions src/Entity/Traits/ExtendedContentTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);

namespace App\Entity\Traits;

trait ExtendedContentTrait
{
/**
* @var array<string, mixed>
* May contain the following properties:
* - boostUsers:
* - desc: list of (followed) users who boosted this item + when it was boosted
* - value: ['user' => User, 'time' => DateTimeImmutable][]
*/
public array $extendedContentProperties = [];
}
29 changes: 29 additions & 0 deletions src/Factory/ExtendedContentPopulationTransformerFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);

namespace App\Factory;

use App\Entity\User;
use App\Pagination\Transformation\ExtendedContentPopulationTransformer;
use App\Repository\Criteria;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;

readonly class ExtendedContentPopulationTransformerFactory
{
public function __construct(
private EntityManagerInterface $entityManager,
private UserRepository $userRepository,
) {
}

public function create(Criteria $criteria, ?User $loggedInUser): ExtendedContentPopulationTransformer
{
return new ExtendedContentPopulationTransformer(
$this->entityManager,
$this->userRepository,
$criteria,
$loggedInUser,
);
}
}
2 changes: 2 additions & 0 deletions src/Form/SettingsType.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
->add('KBIN_FEDERATED_SEARCH_ONLY_LOGGEDIN', CheckboxType::class, ['required' => false])
->add('MBIN_SIDEBAR_SECTIONS_RANDOM_LOCAL_ONLY', CheckboxType::class, ['required' => false])
->add('MBIN_SIDEBAR_SECTIONS_USERS_LOCAL_ONLY', CheckboxType::class, ['required' => false])
->add('MBIN_FEED_ALLOW_ENTRY_COMMENTS', CheckboxType::class, ['required' => false])
->add('MBIN_FEED_ALLOW_POST_COMMENTS', CheckboxType::class, ['required' => false])
->add('MBIN_RESTRICT_MAGAZINE_CREATION', CheckboxType::class, ['required' => false])
->add('MBIN_SSO_SHOW_FIRST', CheckboxType::class, ['required' => false])
->add('MBIN_DOWNVOTES_MODE', ChoiceType::class, [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
use App\Utils\SqlHelpers;
use Doctrine\ORM\EntityManagerInterface;

class ContentPopulationTransformer implements ResultTransformer
readonly class ContentPopulationTransformer implements ResultTransformer
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
protected EntityManagerInterface $entityManager,
) {
}

Expand Down
Loading
Loading