aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/com/juick/server/ActivityPubManager.java26
-rw-r--r--src/main/java/com/juick/server/api/Post.java13
-rw-r--r--src/main/java/com/juick/server/api/activity/model/Context.java1
-rw-r--r--src/main/java/com/juick/server/api/activity/model/activities/Update.java23
-rw-r--r--src/main/java/com/juick/service/activities/ActivityListener.java3
-rw-r--r--src/main/java/com/juick/service/activities/UpdateEvent.java47
-rw-r--r--src/test/java/com/juick/server/MockUpdateListener.java30
-rw-r--r--src/test/java/com/juick/server/tests/ServerTests.java12
8 files changed, 150 insertions, 5 deletions
diff --git a/src/main/java/com/juick/server/ActivityPubManager.java b/src/main/java/com/juick/server/ActivityPubManager.java
index 7c66809e..18470b16 100644
--- a/src/main/java/com/juick/server/ActivityPubManager.java
+++ b/src/main/java/com/juick/server/ActivityPubManager.java
@@ -23,10 +23,7 @@ import com.juick.User;
import com.juick.formatters.PlainTextFormatter;
import com.juick.server.api.SystemActivity.ActivityType;
import com.juick.server.api.activity.model.Context;
-import com.juick.server.api.activity.model.activities.Accept;
-import com.juick.server.api.activity.model.activities.Announce;
-import com.juick.server.api.activity.model.activities.Create;
-import com.juick.server.api.activity.model.activities.Delete;
+import com.juick.server.api.activity.model.activities.*;
import com.juick.server.api.activity.model.objects.Hashtag;
import com.juick.server.api.activity.model.objects.Image;
import com.juick.server.api.activity.model.objects.Mention;
@@ -184,6 +181,27 @@ public class ActivityPubManager implements ActivityListener, NotificationListene
}
@Override
+ public void processUpdateEvent(UpdateEvent event) {
+ String objectUri = event.getMessageUri();
+ User user = event.getUser();
+ String userUri = personUri(user);
+ Person me = (Person) signatureManager.getContext(URI.create(userUri)).get();
+ socialService.getFollowers(user).forEach(acct -> {
+ Person follower = (Person) signatureManager.getContext(URI.create(acct)).get();
+ Update update = new Update();
+ update.setId(objectUri + "#update");
+ update.setActor(me.getId());
+ update.setObject(objectUri);
+ try {
+ logger.info("Update to follower {}", follower.getId());
+ signatureManager.post(me, follower, update);
+ } catch (IOException e) {
+ logger.warn("activitypub exception", e);
+ }
+ });
+ }
+
+ @Override
public void processSystemEvent(SystemEvent systemEvent) {
ActivityType type = systemEvent.getActivity().getType();
if (type.equals(ActivityType.message)) {
diff --git a/src/main/java/com/juick/server/api/Post.java b/src/main/java/com/juick/server/api/Post.java
index 72a9c383..37b40b2d 100644
--- a/src/main/java/com/juick/server/api/Post.java
+++ b/src/main/java/com/juick/server/api/Post.java
@@ -22,6 +22,7 @@ import com.juick.Reaction;
import com.juick.Status;
import com.juick.User;
import com.juick.model.CommandResult;
+import com.juick.server.ActivityPubManager;
import com.juick.server.CommandsManager;
import com.juick.server.util.HttpBadRequestException;
import com.juick.server.util.HttpForbiddenException;
@@ -29,11 +30,13 @@ import com.juick.server.util.HttpNotFoundException;
import com.juick.server.util.HttpUtils;
import com.juick.service.MessagesService;
import com.juick.service.UserService;
+import com.juick.service.activities.UpdateEvent;
import com.juick.service.security.annotation.Visitor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
@@ -61,6 +64,10 @@ public class Post {
private String tmpDir;
@Inject
CommandsManager commandsManager;
+ @Inject
+ ApplicationEventPublisher applicationEventPublisher;
+ @Inject
+ ActivityPubManager activityPubManager;
@RequestMapping(value = "/api/post", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(value = HttpStatus.OK)
@@ -217,7 +224,11 @@ public class Post {
User author = rid == 0 ? messagesService.getMessageAuthor(mid) : messagesService.getReply(mid, rid).getUser();
if (visitor.equals(author)) {
if (messagesService.updateMessage(mid, rid, body)) {
- Message result = rid == 0 ? messagesService.getMessage(mid).orElseThrow(IllegalStateException::new) : messagesService.getReply(mid, rid);
+ Message result = rid == 0 ?
+ messagesService.getMessage(mid).orElseThrow(IllegalStateException::new)
+ : messagesService.getReply(mid, rid);
+ applicationEventPublisher.publishEvent(
+ new UpdateEvent(this, author, activityPubManager.messageUri(mid, rid)));
return CommandResult.build(result, "Message updated", StringUtils.EMPTY);
}
throw new HttpBadRequestException();
diff --git a/src/main/java/com/juick/server/api/activity/model/Context.java b/src/main/java/com/juick/server/api/activity/model/Context.java
index 04cddb11..14b65e25 100644
--- a/src/main/java/com/juick/server/api/activity/model/Context.java
+++ b/src/main/java/com/juick/server/api/activity/model/Context.java
@@ -33,6 +33,7 @@ import java.util.List;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property="type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Create.class, name = "Create"),
+ @JsonSubTypes.Type(value = Update.class, name = "Update"),
@JsonSubTypes.Type(value = Delete.class, name = "Delete"),
@JsonSubTypes.Type(value = Follow.class, name = "Follow"),
@JsonSubTypes.Type(value = Accept.class, name = "Accept"),
diff --git a/src/main/java/com/juick/server/api/activity/model/activities/Update.java b/src/main/java/com/juick/server/api/activity/model/activities/Update.java
new file mode 100644
index 00000000..17dfc105
--- /dev/null
+++ b/src/main/java/com/juick/server/api/activity/model/activities/Update.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2008-2019, Juick
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.juick.server.api.activity.model.activities;
+
+import com.juick.server.api.activity.model.Activity;
+
+public class Update extends Activity {
+}
diff --git a/src/main/java/com/juick/service/activities/ActivityListener.java b/src/main/java/com/juick/service/activities/ActivityListener.java
index d32585bb..81190ef2 100644
--- a/src/main/java/com/juick/service/activities/ActivityListener.java
+++ b/src/main/java/com/juick/service/activities/ActivityListener.java
@@ -39,4 +39,7 @@ public interface ActivityListener {
@Async
@EventListener
void undoAnnounceEvent(UndoAnnounceEvent event);
+ @Async
+ @EventListener
+ void processUpdateEvent(UpdateEvent event);
}
diff --git a/src/main/java/com/juick/service/activities/UpdateEvent.java b/src/main/java/com/juick/service/activities/UpdateEvent.java
new file mode 100644
index 00000000..0d02e80b
--- /dev/null
+++ b/src/main/java/com/juick/service/activities/UpdateEvent.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008-2019, Juick
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.juick.service.activities;
+
+import com.juick.User;
+import org.springframework.context.ApplicationEvent;
+
+public class UpdateEvent extends ApplicationEvent {
+ private final User actor;
+ private final String messageUri;
+ /**
+ * Create a new {@code ApplicationEvent}.
+ *
+ * @param source the object on which the event initially occurred or with
+ * which the event is associated (never {@code null})
+ * @param actor the event author
+ * @param messageUri the object's id
+ */
+ public UpdateEvent(Object source, User actor, String messageUri) {
+ super(source);
+ this.actor = actor;
+ this.messageUri = messageUri;
+ }
+
+ public User getUser() {
+ return actor;
+ }
+
+ public String getMessageUri() {
+ return messageUri;
+ }
+}
diff --git a/src/test/java/com/juick/server/MockUpdateListener.java b/src/test/java/com/juick/server/MockUpdateListener.java
new file mode 100644
index 00000000..08742b12
--- /dev/null
+++ b/src/test/java/com/juick/server/MockUpdateListener.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008-2019, Juick
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.juick.server;
+
+import com.juick.service.activities.UpdateEvent;
+import org.springframework.context.ApplicationListener;
+
+import javax.annotation.Nonnull;
+
+public class MockUpdateListener implements ApplicationListener<UpdateEvent> {
+ @Override
+ public void onApplicationEvent(@Nonnull UpdateEvent event) {
+
+ }
+}
diff --git a/src/test/java/com/juick/server/tests/ServerTests.java b/src/test/java/com/juick/server/tests/ServerTests.java
index 479ec750..01f9812c 100644
--- a/src/test/java/com/juick/server/tests/ServerTests.java
+++ b/src/test/java/com/juick/server/tests/ServerTests.java
@@ -48,6 +48,8 @@ import com.juick.server.util.HttpUtils;
import com.juick.server.util.ImageUtils;
import com.juick.server.www.WebApp;
import com.juick.service.*;
+import com.juick.service.activities.ActivityListener;
+import com.juick.service.activities.UpdateEvent;
import com.juick.service.component.SystemEvent;
import com.juick.test.util.MockUtils;
import com.juick.util.DateFormattersHolder;
@@ -1301,6 +1303,11 @@ public class ServerTests {
assertThat(replyJpgCmyk.getNewMessage().get().getAttachmentType(), is("jpg"));
}
+ @MockBean
+ private MockUpdateListener activityListener;
+ @Captor
+ protected ArgumentCaptor<UpdateEvent> updateEventCaptor;
+
@Test
public void messageEditingSpec() throws Exception {
MvcResult result = mockMvc.perform(post("/api/post").with(httpBasic(ugnichName, ugnichPassword))
@@ -1318,6 +1325,11 @@ public class ServerTests {
.getNewMessage().get();
assertThat(edited.getText(), equalTo("PEOPLE"));
assertThat(edited.getUpdatedAt(), greaterThan(edited.getCreated()));
+ Mockito.verify(activityListener, Mockito.times(1))
+ .onApplicationEvent(updateEventCaptor.capture());
+ UpdateEvent updateEvent = updateEventCaptor.getValue();
+ assertThat(updateEvent.getUser(), is(ugnich));
+ assertThat(activityPubManager.messageUri(original.getMid(), 0), is(updateEvent.getMessageUri()));
mockMvc.perform(post("/api/update").with(httpBasic(freefdName, freefdPassword))
.param("mid", String.valueOf(original.getMid()))
.param("body", "PEOPLE")).andExpect(status().is(403));