Skip to content

Commit 4e005cb

Browse files
Fix missing Update activity add cover and avatar removal (#1492)
Co-authored-by: Melroy van den Berg <[email protected]>
1 parent 207ec5f commit 4e005cb

File tree

8 files changed

+83
-7
lines changed

8 files changed

+83
-7
lines changed

src/Controller/Api/User/UserDeleteImagesApi.php

+13-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace App\Controller\Api\User;
66

77
use App\DTO\UserResponseDto;
8+
use App\Event\User\UserEditedEvent;
89
use App\Factory\UserFactory;
910
use App\Service\UserManager;
1011
use Nelmio\ApiDocBundle\Attribute\Model;
@@ -51,7 +52,12 @@ public function avatar(
5152
): JsonResponse {
5253
$headers = $this->rateLimit($apiImageLimiter);
5354

54-
$manager->detachAvatar($this->getUserOrThrow());
55+
$user = $this->getUserOrThrow();
56+
$manager->detachAvatar($user);
57+
/*
58+
* Call edit so the @see UserEditedEvent is triggered and the changes are federated
59+
*/
60+
$manager->edit($user, $manager->createDto($user));
5561

5662
return new JsonResponse(
5763
$this->serializeUser($factory->createDto($this->getUserOrThrow())),
@@ -94,7 +100,12 @@ public function cover(
94100
): JsonResponse {
95101
$headers = $this->rateLimit($apiImageLimiter);
96102

97-
$manager->detachCover($this->getUserOrThrow());
103+
$user = $this->getUserOrThrow();
104+
$manager->detachCover($user);
105+
/*
106+
* Call edit so the @see UserEditedEvent is triggered and the changes are federated
107+
*/
108+
$manager->edit($user, $manager->createDto($user));
98109

99110
return new JsonResponse(
100111
$this->serializeUser($factory->createDto($this->getUserOrThrow())),

src/Controller/User/Profile/UserEditController.php

+7
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66

77
use App\Controller\AbstractController;
88
use App\DTO\UserDto;
9+
use App\Exception\ImageDownloadTooLargeException;
910
use App\Form\UserBasicType;
1011
use App\Form\UserEmailType;
1112
use App\Form\UserPasswordType;
13+
use App\Service\SettingsManager;
1214
use App\Service\UserManager;
1315
use Symfony\Bundle\SecurityBundle\Security;
1416
use Symfony\Component\Form\FormError;
@@ -27,6 +29,7 @@ public function __construct(
2729
private readonly UserPasswordHasherInterface $userPasswordHasher,
2830
private readonly TranslatorInterface $translator,
2931
private readonly Security $security,
32+
private readonly SettingsManager $settingsManager,
3033
) {
3134
}
3235

@@ -176,6 +179,10 @@ private function handleForm(
176179
}
177180

178181
return $form;
182+
} catch (ImageDownloadTooLargeException $e) {
183+
$this->addFlash('error', $this->translator->trans('flash_image_download_too_large_error', ['%bytes%' => $this->settingsManager->getMaxImageByteString()]));
184+
185+
return null;
179186
} catch (\Exception $e) {
180187
return null;
181188
}

src/Controller/User/UserAvatarDeleteController.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ public function __invoke(Request $request): Response
2222
{
2323
$this->denyAccessUnlessGranted('edit_profile', $this->getUserOrThrow());
2424

25-
$this->userManager->detachAvatar($this->getUserOrThrow());
25+
$user = $this->getUserOrThrow();
26+
$this->userManager->detachAvatar($user);
27+
/*
28+
* Call edit so the @see UserEditedEvent is triggered and the changes are federated
29+
*/
30+
$this->userManager->edit($user, $this->userManager->createDto($user));
2631

2732
if ($request->isXmlHttpRequest()) {
2833
return new JsonResponse(

src/Controller/User/UserCoverDeleteController.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ public function __invoke(Request $request): Response
2222
{
2323
$this->denyAccessUnlessGranted('edit_profile', $this->getUserOrThrow());
2424

25-
$this->userManager->detachCover($this->getUserOrThrow());
25+
$user = $this->getUserOrThrow();
26+
$this->userManager->detachCover($user);
27+
/*
28+
* Call edit so the @see UserEditedEvent is triggered and the changes are federated
29+
*/
30+
$this->userManager->edit($user, $this->userManager->createDto($user));
2631

2732
if ($request->isXmlHttpRequest()) {
2833
return new JsonResponse(

src/MessageHandler/ActivityPub/Outbox/UpdateHandler.php

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use App\Service\DeliverManager;
2424
use App\Service\SettingsManager;
2525
use Doctrine\ORM\EntityManagerInterface;
26+
use Psr\Log\LoggerInterface;
2627
use Symfony\Component\HttpKernel\KernelInterface;
2728
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
2829

@@ -38,6 +39,7 @@ public function __construct(
3839
private readonly DeliverManager $deliverManager,
3940
private readonly UpdateWrapper $updateWrapper,
4041
private readonly KernelInterface $kernel,
42+
private readonly LoggerInterface $logger,
4143
) {
4244
parent::__construct($this->entityManager, $this->kernel);
4345
}
@@ -88,6 +90,7 @@ public function doWork(MessageInterface $message): void
8890
$activity = $this->updateWrapper->buildForActor($entity, $editedByUser);
8991
if ($entity instanceof User) {
9092
$inboxes = $this->userRepository->findAudience($entity);
93+
$this->logger->debug('[UpdateHandler::doWork] sending update user activity for user {u} to {i}', ['u' => $entity->username, 'i' => join(', ', $inboxes)]);
9194
} elseif ($entity instanceof Magazine) {
9295
if ('random' === $entity->name) {
9396
// do not federate the random magazine

src/Service/ActivityPubManager.php

+9
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,9 @@ private function updateUser(string $actorUrl): ?User
409409
$this->bus->dispatch(new DeleteImageMessage($user->avatar->getId()));
410410
}
411411
$user->avatar = $newImage;
412+
} elseif (null !== $user->avatar) {
413+
$this->bus->dispatch(new DeleteImageMessage($user->avatar->getId()));
414+
$user->avatar = null;
412415
}
413416

414417
// Only update cover if image is set
@@ -421,6 +424,9 @@ private function updateUser(string $actorUrl): ?User
421424
$this->bus->dispatch(new DeleteImageMessage($user->cover->getId()));
422425
}
423426
$user->cover = $newImage;
427+
} elseif (null !== $user->cover) {
428+
$this->bus->dispatch(new DeleteImageMessage($user->cover->getId()));
429+
$user->cover = null;
424430
}
425431

426432
if (null !== $user->apFollowersUrl) {
@@ -565,6 +571,9 @@ private function updateMagazine(string $actorUrl): ?Magazine
565571
$this->bus->dispatch(new DeleteImageMessage($magazine->icon->getId()));
566572
}
567573
$magazine->icon = $newImage;
574+
} elseif (null !== $magazine->icon) {
575+
$this->bus->dispatch(new DeleteImageMessage($magazine->icon->getId()));
576+
$magazine->icon = null;
568577
}
569578

570579
if ($actor['name']) {

templates/user/settings/profile.html.twig

+37-3
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,54 @@
2929
{{ form_start(form) }}
3030
{{ component('editor_toolbar', {id: 'user_basic_about'}) }}
3131
{{ form_row(form.about, {label: false, attr: {
32-
placeholder: 'about',
33-
'data-controller': 'input-length rich-textarea autogrow',
32+
placeholder: 'about',
33+
'data-controller': 'input-length rich-textarea autogrow',
3434
'data-entry-link-create-target': 'user_about',
3535
'data-action' : 'input-length#updateDisplay',
3636
'data-input-length-max-value' : constant('App\\DTO\\UserDto::MAX_ABOUT_LENGTH')
3737
}}) }}
3838
{{ form_row(form.username, {label: 'username', attr: {
39-
'data-controller': 'input-length autogrow',
39+
'data-controller': 'input-length autogrow',
4040
'data-entry-link-create-target': 'user_about',
4141
'data-action' : 'input-length#updateDisplay',
4242
'data-input-length-max-value' : constant('App\\DTO\\UserDto::MAX_USERNAME_LENGTH')
4343
}}) }}
4444
{{ form_row(form.avatar, {label: 'avatar'}) }}
45+
{% if app.user.avatar is not same as null %}
46+
<div class="actions">
47+
<ul style="width: 100%">
48+
<img width="40"
49+
height="40"
50+
src="{{ asset(app.user.avatar.filePath)|imagine_filter('entry_thumb') }}"
51+
alt="{{ app.user.avatar.altText }}" />
52+
<button formaction="{{ path('user_settings_avatar_delete') }}"
53+
class="btn-link"
54+
aria-label="{{ 'remove_user_avatar'|trans }}"
55+
title="{{ 'remove_user_avatar'|trans }}"
56+
data-action="confirmation#ask" data-confirmation-message-param="{{ 'are_you_sure'|trans }}">
57+
<i class="fa-solid fa-xmark" aria-hidden="true"></i>
58+
</button>
59+
</ul>
60+
</div>
61+
{% endif %}
4562
{{ form_row(form.cover, {label: 'cover'}) }}
63+
{% if app.user.cover is not same as null %}
64+
<div class="actions">
65+
<ul style="width: 100%">
66+
<img width="40"
67+
height="40"
68+
src="{{ asset(app.user.cover.filePath)|imagine_filter('entry_thumb') }}"
69+
alt="{{ app.user.cover.altText }}" />
70+
<button formaction="{{ path('user_settings_cover_delete') }}"
71+
class="btn-link"
72+
aria-label="{{ 'remove_user_cover'|trans }}"
73+
title="{{ 'remove_user_cover'|trans }}"
74+
data-action="confirmation#ask" data-confirmation-message-param="{{ 'are_you_sure'|trans }}">
75+
<i class="fa-solid fa-xmark" aria-hidden="true"></i>
76+
</button>
77+
</ul>
78+
</div>
79+
{% endif %}
4680
<div class="row actions">
4781
{{ form_row(form.submit, {label: 'save', attr: {class: 'btn btn__primary'}}) }}
4882
</div>

translations/messages.en.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ add_comment: Add comment
5353
add_post: Add post
5454
add_media: Add media
5555
remove_media: Remove media
56+
remove_user_avatar: Remove avatar
57+
remove_user_cover: Remove cover
5658
markdown_howto: How does the editor work?
5759
enter_your_comment: Enter your comment
5860
enter_your_post: Enter your post

0 commit comments

Comments
 (0)