From cdfc8171036f52d8b69861125e7a05a9b7314a2c Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Fri, 13 Jan 2023 21:08:01 +0300 Subject: Mastodon API: posting and minor fixes to make Tusky happy --- src/main/java/com/juick/www/api/Mastodon.java | 68 ++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 6 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/com/juick/www/api/Mastodon.java b/src/main/java/com/juick/www/api/Mastodon.java index c595bb19..a190defe 100644 --- a/src/main/java/com/juick/www/api/Mastodon.java +++ b/src/main/java/com/juick/www/api/Mastodon.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; import com.juick.ActivityPubManager; +import com.juick.CommandsManager; import com.juick.model.Chat; import com.juick.model.Message; import com.juick.model.User; @@ -31,6 +32,7 @@ import com.juick.service.TagService; import com.juick.service.UserService; import com.juick.util.HttpBadRequestException; import com.juick.util.MessageUtils; +import com.juick.util.formatters.PlainTextFormatter; import com.juick.www.WebApp; import com.juick.www.api.activity.helpers.ProfileUriBuilder; import io.swagger.v3.oas.annotations.Parameter; @@ -49,6 +51,7 @@ import org.springframework.security.oauth2.server.authorization.settings.TokenSe import org.springframework.web.bind.annotation.*; import javax.inject.Inject; +import java.net.URI; import java.time.Duration; import java.time.Instant; import java.util.*; @@ -66,7 +69,7 @@ public class Mastodon { @Inject RegisteredClientRepository registeredClientRepository; @Inject - TagService tagService; + CommandsManager commandsManager; @Inject ChatService chatService; @Inject @@ -96,6 +99,7 @@ public class Mastodon { @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public record CredentialAccount(String id, String username, String acct, + String url, String displayName, Integer followersCount, Integer followingCount, @@ -228,9 +232,19 @@ public class Mastodon { } @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) - public record Status(String id, Instant createdAt, CredentialAccount account, String inReplyToId, String inReplyToAccountId, - Boolean sensitive, String spoilerText, String visibility, String content, - List mediaAttachments) { + public record Tag(String name, String url) {} + + public Tag toTag(com.juick.model.Tag juickTag) { + return new Tag(juickTag.getName(), profileUriBuilder.tagUri(juickTag)); + } + + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) + public record Status(String id, String url, Instant createdAt, CredentialAccount account, String inReplyToId, String inReplyToAccountId, + Boolean sensitive, @JsonInclude String spoilerText, String visibility, String content, + @JsonInclude List mediaAttachments, + @JsonInclude List mentions, + @JsonInclude List emojis, + @JsonInclude List tags) { } @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) @@ -247,6 +261,7 @@ public class Mastodon { String.valueOf(user.getUid()), user.getName(), user.getName(), + profileUriBuilder.personWebUri(user), user.getFullName(), userService.getUserReaders(user.getUid()).size(), userService.getUserFriends(user.getUid()).size(), @@ -258,6 +273,7 @@ public class Mastodon { public Status mapLastMessage(Chat chat) { return new Status( String.valueOf(chat.getLastMessageTimestamp().toEpochMilli()), + "https://juick.com/pm/inbox", chat.getLastMessageTimestamp(), toAccount(chat), null, @@ -266,7 +282,7 @@ public class Mastodon { "", "direct", chat.getLastMessageText(), - List.of() + List.of(), List.of(), List.of(), List.of() ); } @@ -301,6 +317,7 @@ public class Mastodon { : List.of(); return new Status( ProfileUriBuilder.messageId(message), + PlainTextFormatter.formatUrl(message), message.getCreated(), toAccount(message.getUser()), message.getReplyto() > 0 ? ProfileUriBuilder.messageId(message.getMid(), message.getReplyto()) : null, @@ -309,7 +326,8 @@ public class Mastodon { "", "public", activityPubManager.htmlLayout(message, profileUriBuilder.baseUri()), - attachments + attachments, + List.of(), List.of(), message.getTags().stream().map(this::toTag).collect(Collectors.toList()) ); } @@ -357,4 +375,42 @@ public class Mastodon { .map(this::toStatus).toList(); return new Context(List.of(), thread); } + + private Status post(User visitor, String status, String inReplyToId) throws Exception { + if (StringUtils.isNotEmpty(inReplyToId)) { + var message = activityPubManager.findMessage(inReplyToId); + var command = MessageUtils.isReply(message) ? + String.format("#%d/%d %s", message.getMid(), message.getRid(), status) + : String.format("#%d %s", message.getMid(), status); + var result = commandsManager.processCommand( + visitor, command, URI.create(StringUtils.EMPTY)); + if (result.getNewMessage().isPresent()) { + return toStatus(result.getNewMessage().get()); + } else { + throw new HttpBadRequestException(); + } + } else { + var result = commandsManager.processCommand(visitor, status, URI.create(StringUtils.EMPTY)); + if (result.getNewMessage().isPresent()) { + return toStatus(result.getNewMessage().get()); + } else { + throw new HttpBadRequestException(); + } + } + } + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) + public record NewStatus(String status, @JsonProperty("in_reply_to_id") String inReplyToId) {} + + @PostMapping(value = "/api/v1/statuses", consumes = MediaType.APPLICATION_JSON_VALUE) + public Status postStatus(User visitor, @RequestBody NewStatus newStatus) throws Exception { + return post(visitor, newStatus.status(), newStatus.inReplyToId()); + } + @PostMapping(value = "/api/v1/statuses", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, + MediaType.MULTIPART_FORM_DATA_VALUE}) + public Status postStatus( + User visitor, + @RequestParam(required = false) String status, + @RequestParam(name = "in_reply_to_id", required = false) String inReplyToId) throws Exception { + return post(visitor, status, inReplyToId); + } } -- cgit v1.2.3