From 7a2f89266c8f6337e4e81a2fd8488e0f80f4f9bd Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Fri, 3 Apr 2020 23:53:23 +0300 Subject: Reorganize layout and code cleanup --- .../java/com/juick/www/api/activity/Profile.java | 410 +++++++++++++++++++++ .../activity/helpers/ActivityIdDeserializer.java | 38 ++ .../activity/helpers/LinkValueDeserializer.java | 38 ++ .../com/juick/www/api/activity/model/Activity.java | 50 +++ .../com/juick/www/api/activity/model/Context.java | 144 ++++++++ .../www/api/activity/model/activities/Accept.java | 23 ++ .../api/activity/model/activities/Announce.java | 23 ++ .../www/api/activity/model/activities/Block.java | 23 ++ .../www/api/activity/model/activities/Create.java | 23 ++ .../www/api/activity/model/activities/Delete.java | 23 ++ .../www/api/activity/model/activities/Follow.java | 23 ++ .../www/api/activity/model/activities/Like.java | 23 ++ .../www/api/activity/model/activities/Undo.java | 23 ++ .../www/api/activity/model/activities/Update.java | 23 ++ .../www/api/activity/model/objects/Emoji.java | 23 ++ .../www/api/activity/model/objects/Hashtag.java | 28 ++ .../www/api/activity/model/objects/Image.java | 32 ++ .../juick/www/api/activity/model/objects/Key.java | 41 +++ .../juick/www/api/activity/model/objects/Link.java | 32 ++ .../www/api/activity/model/objects/Mention.java | 29 ++ .../juick/www/api/activity/model/objects/Note.java | 81 ++++ .../activity/model/objects/OrderedCollection.java | 42 +++ .../model/objects/OrderedCollectionPage.java | 75 ++++ .../www/api/activity/model/objects/Person.java | 104 ++++++ 24 files changed, 1374 insertions(+) create mode 100644 src/main/java/com/juick/www/api/activity/Profile.java create mode 100644 src/main/java/com/juick/www/api/activity/helpers/ActivityIdDeserializer.java create mode 100644 src/main/java/com/juick/www/api/activity/helpers/LinkValueDeserializer.java create mode 100644 src/main/java/com/juick/www/api/activity/model/Activity.java create mode 100644 src/main/java/com/juick/www/api/activity/model/Context.java create mode 100644 src/main/java/com/juick/www/api/activity/model/activities/Accept.java create mode 100644 src/main/java/com/juick/www/api/activity/model/activities/Announce.java create mode 100644 src/main/java/com/juick/www/api/activity/model/activities/Block.java create mode 100644 src/main/java/com/juick/www/api/activity/model/activities/Create.java create mode 100644 src/main/java/com/juick/www/api/activity/model/activities/Delete.java create mode 100644 src/main/java/com/juick/www/api/activity/model/activities/Follow.java create mode 100644 src/main/java/com/juick/www/api/activity/model/activities/Like.java create mode 100644 src/main/java/com/juick/www/api/activity/model/activities/Undo.java create mode 100644 src/main/java/com/juick/www/api/activity/model/activities/Update.java create mode 100644 src/main/java/com/juick/www/api/activity/model/objects/Emoji.java create mode 100644 src/main/java/com/juick/www/api/activity/model/objects/Hashtag.java create mode 100644 src/main/java/com/juick/www/api/activity/model/objects/Image.java create mode 100644 src/main/java/com/juick/www/api/activity/model/objects/Key.java create mode 100644 src/main/java/com/juick/www/api/activity/model/objects/Link.java create mode 100644 src/main/java/com/juick/www/api/activity/model/objects/Mention.java create mode 100644 src/main/java/com/juick/www/api/activity/model/objects/Note.java create mode 100644 src/main/java/com/juick/www/api/activity/model/objects/OrderedCollection.java create mode 100644 src/main/java/com/juick/www/api/activity/model/objects/OrderedCollectionPage.java create mode 100644 src/main/java/com/juick/www/api/activity/model/objects/Person.java (limited to 'src/main/java/com/juick/www/api/activity') diff --git a/src/main/java/com/juick/www/api/activity/Profile.java b/src/main/java/com/juick/www/api/activity/Profile.java new file mode 100644 index 00000000..bdd7cab2 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/Profile.java @@ -0,0 +1,410 @@ +/* + * 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 . + */ + +package com.juick.www.api.activity; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.juick.model.Message; +import com.juick.model.User; +import com.juick.formatters.PlainTextFormatter; +import com.juick.model.CommandResult; +import com.juick.server.ActivityPubManager; +import com.juick.server.CommandsManager; +import com.juick.server.KeystoreManager; +import com.juick.server.SignatureManager; +import com.juick.www.api.activity.model.Activity; +import com.juick.www.api.activity.model.Context; +import com.juick.www.api.activity.model.activities.Announce; +import com.juick.www.api.activity.model.activities.Create; +import com.juick.www.api.activity.model.activities.Delete; +import com.juick.www.api.activity.model.activities.Follow; +import com.juick.www.api.activity.model.activities.Like; +import com.juick.www.api.activity.model.activities.Undo; +import com.juick.www.api.activity.model.objects.Image; +import com.juick.www.api.activity.model.objects.Key; +import com.juick.www.api.activity.model.objects.Note; +import com.juick.www.api.activity.model.objects.OrderedCollection; +import com.juick.www.api.activity.model.objects.OrderedCollectionPage; +import com.juick.www.api.activity.model.objects.Person; +import com.juick.server.util.HttpNotFoundException; +import com.juick.www.WebApp; +import com.juick.service.MessagesService; +import com.juick.service.UserService; +import com.juick.service.activities.AnnounceEvent; +import com.juick.service.activities.FollowEvent; +import com.juick.service.activities.UndoAnnounceEvent; +import com.juick.service.activities.UndoFollowEvent; +import com.juick.service.security.annotation.Visitor; +import com.overzealous.remark.Remark; +import org.apache.commons.io.IOUtils; +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.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; +import org.springframework.web.util.UriComponentsBuilder; + +import javax.inject.Inject; +import java.io.InputStream; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@RestController +public class Profile { + private static final Logger logger = LoggerFactory.getLogger("ActivityPub"); + @Inject + private UserService userService; + @Inject + private MessagesService messagesService; + @Inject + private KeystoreManager keystoreManager; + @Inject + private SignatureManager signatureManager; + @Inject + private ActivityPubManager activityPubManager; + @Inject + private ApplicationEventPublisher applicationEventPublisher; + @Inject + private CommandsManager commandsManager; + @Value("${web_domain:localhost}") + private String domain; + @Value("${ap_base_uri:http://localhost:8080/}") + private String baseUri; + @Inject + private ObjectMapper jsonMapper; + @Inject + private WebApp webApp; + @Inject + private Remark remarkConverter; + + @GetMapping(value = "/u/{userName}", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE}) + public Person getUser(@PathVariable String userName) { + User user = userService.getUserByName(userName); + if (!user.isAnonymous()) { + Person person = new Person(); + person.setId(activityPubManager.personUri(user)); + person.setUrl(activityPubManager.personWebUri(user)); + person.setName(userName); + person.setPreferredUsername(userName); + Key publicKey = new Key(); + publicKey.setId(person.getId() + "#main-key"); + publicKey.setOwner(person.getId()); + publicKey.setPublicKeyPem(keystoreManager.getPublicKeyPem()); + person.setPublicKey(publicKey); + person.setInbox(activityPubManager.inboxUri()); + person.setOutbox(activityPubManager.outboxUri(user)); + person.setFollowers(activityPubManager.followersUri(user)); + person.setFollowing(activityPubManager.followingUri(user)); + Image avatar = new Image(); + avatar.setUrl(webApp.getAvatarUrl(user)); + avatar.setMediaType("image/png"); + person.setIcon(avatar); + return (Person) Context.build(person); + } + throw new HttpNotFoundException(); + } + + @GetMapping(value = "/u/{userName}/blog/toc", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE}) + public OrderedCollection getOutbox(@PathVariable String userName) { + User user = userService.getUserByName(userName); + if (!user.isAnonymous()) { + UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(baseUri); + OrderedCollection blog = new OrderedCollection(); + blog.setId(ServletUriComponentsBuilder.fromCurrentRequestUri().toUriString()); + blog.setTotalItems(userService.getStatsMessages(user.getUid())); + blog.setFirst(uriComponentsBuilder.path(String.format("/u/%s/blog", userName)).toUriString()); + return (OrderedCollection) Context.build(blog); + } + throw new HttpNotFoundException(); + } + + @GetMapping(value = "/u/{userName}/blog", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE}) + public OrderedCollectionPage getOutboxPage(@Visitor User visitor, @PathVariable String userName, + @RequestParam(required = false, defaultValue = "0") int before) { + User user = userService.getUserByName(userName); + if (!user.isAnonymous() && !user.isBanned()) { + UriComponentsBuilder uri = UriComponentsBuilder.fromUriString(baseUri); + String personUri = uri.path(String.format("/u/%s", userName)).toUriString(); + List mids = messagesService.getUserBlog(user.getUid(), 0, before); + List notes = messagesService.getMessages(visitor, mids) + .stream().map(activityPubManager::makeNote).collect(Collectors.toList()); + OrderedCollectionPage page = new OrderedCollectionPage(); + page.setPartOf(uri.replacePath(String.format("/u/%s/blog/toc", userName)).toUriString()); + page.setFirst(uri.replacePath(String.format("/u/%s/blog", userName)).toUriString()); + page.setId(ServletUriComponentsBuilder.fromCurrentRequestUri().toUriString()); + page.setOrderedItems(notes.stream().map(a -> { + Create create = new Create(); + create.setId(a.getId() + "#Create"); + create.setTo(a.getTo()); + create.setActor(personUri); + create.setObject(a); + create.setPublished(a.getPublished()); + return create; + }).collect(Collectors.toList())); + int beforeNext = mids.stream().reduce((fst, second) -> second).orElse(0); + if (beforeNext > 0) { + page.setNext(uri.queryParam("before", beforeNext).toUriString()); + } + page.setLast(uri.replaceQueryParam("before", "1").toUriString()); + return (OrderedCollectionPage) Context.build(page); + } + throw new HttpNotFoundException(); + } + + @GetMapping(value = "/u/{userName}/followers/toc", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE}) + public OrderedCollection getFollowers(@PathVariable String userName) { + User user = userService.getUserByName(userName); + if (!user.isAnonymous()) { + UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(baseUri); + OrderedCollection followers = new OrderedCollection(); + followers.setId(ServletUriComponentsBuilder.fromCurrentRequestUri().toUriString()); + followers.setTotalItems(userService.getStatsMyReaders(user.getUid())); + followers.setFirst(uriComponentsBuilder.path(String.format("/u/%s/followers", userName)).toUriString()); + return (OrderedCollection) Context.build(followers); + } + throw new HttpNotFoundException(); + } + + @GetMapping(value = "/u/{userName}/followers", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE}) + public OrderedCollectionPage getFollowersPage(@PathVariable String userName, + @RequestParam(required = false, defaultValue = "0") int page) { + User user = userService.getUserByName(userName); + if (!user.isAnonymous()) { + UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(baseUri); + uriComponentsBuilder.path(String.format("/u/%s/followers", userName)); + List followers = userService.getUserReaders(user.getUid()); + Stream followersPage = followers.stream().skip(20 * page).limit(20); + + OrderedCollectionPage result = new OrderedCollectionPage(); + result.setId(ServletUriComponentsBuilder.fromCurrentRequestUri().toUriString()); + result.setOrderedItems(followersPage.map(a -> { + Person follower = new Person(); + follower.setName(a.getName()); + follower.setPreferredUsername(a.getName()); + follower.setUrl(activityPubManager.personWebUri(a)); + return follower; + }).collect(Collectors.toList())); + boolean hasNext = followers.size() <= 20 * page; + if (hasNext) { + result.setNext(uriComponentsBuilder.queryParam("page", page + 1).toUriString()); + } + return (OrderedCollectionPage) Context.build(result); + } + throw new HttpNotFoundException(); + } + + @GetMapping(value = "/u/{userName}/following/toc", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE}) + public OrderedCollection getFollowing(@PathVariable String userName) { + User user = userService.getUserByName(userName); + if (!user.isAnonymous()) { + UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(baseUri); + OrderedCollection following = new OrderedCollection(); + following.setId(ServletUriComponentsBuilder.fromCurrentRequestUri().toUriString()); + following.setTotalItems(userService.getUserFriends(user.getUid()).size()); + following.setFirst(uriComponentsBuilder.path(String.format("/u/%s/followers", userName)).toUriString()); + return (OrderedCollection) Context.build(following); + } + throw new HttpNotFoundException(); + } + + @GetMapping(value = "/u/{userName}/following", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE}) + public OrderedCollectionPage getFollowingPage(@PathVariable String userName, + @RequestParam(required = false, defaultValue = "0") int page) { + User user = userService.getUserByName(userName); + if (!user.isAnonymous()) { + UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(baseUri); + uriComponentsBuilder.path(String.format("/u/%s/following", userName)); + List following = userService.getUserFriends(user.getUid()); + Stream followingPage = following.stream().skip(20 * page).limit(20); + + OrderedCollectionPage result = new OrderedCollectionPage(); + result.setId(ServletUriComponentsBuilder.fromCurrentRequestUri().toUriString()); + result.setOrderedItems(followingPage.map(a -> { + Person follower = new Person(); + follower.setName(a.getName()); + follower.setPreferredUsername(a.getName()); + follower.setUrl(activityPubManager.personWebUri(a)); + return follower; + }).collect(Collectors.toList())); + boolean hasNext = following.size() <= 20 * page; + if (hasNext) { + result.setNext(uriComponentsBuilder.queryParam("page", page + 1).toUriString()); + } + return (OrderedCollectionPage) Context.build(result); + } + throw new HttpNotFoundException(); + } + + @GetMapping(value = "/n/{mid}-{rid}", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE}) + public Context showNote(@PathVariable int mid, @PathVariable int rid) { + if (rid > 0) { + // reply + return Context.build(activityPubManager.makeNote( + messagesService.getReply(mid, rid))); + } + return Context.build(activityPubManager.makeNote( + messagesService.getMessage(mid).orElseThrow(IllegalStateException::new))); + } + + @PostMapping(value = "/api/inbox", consumes = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE}) + public ResponseEntity processInbox( + @Visitor User visitor, + InputStream inboxData) throws Exception { + String inbox = IOUtils.toString(inboxData, StandardCharsets.UTF_8); + logger.info("Inbox: {}", inbox); + Activity activity = jsonMapper.readValue(inbox, Activity.class); + if ((StringUtils.isNotEmpty(visitor.getUri().toString()) + && visitor.getUri().equals(URI.create(activity.getActor()))) + || !visitor.isAnonymous()) { + if (activity instanceof Follow) { + Follow followRequest = (Follow) activity; + applicationEventPublisher.publishEvent( + new FollowEvent(this, followRequest)); + return new ResponseEntity<>(CommandResult.fromString("Follow request accepted"), HttpStatus.ACCEPTED); + + } + if (activity instanceof Undo) { + Map object = (Map) activity.getObject(); + String objectType = (String) object.get("type"); + String objectObject = (String) object.get("object"); + if (objectType.equals("Follow")) { + applicationEventPublisher.publishEvent(new UndoFollowEvent(this, activity.getActor(), objectObject)); + return new ResponseEntity<>(CommandResult.fromString("Undo follow request accepted"), HttpStatus.OK); + } else if (objectType.equals("Like") || objectType.equals("Announce")) { + applicationEventPublisher.publishEvent(new UndoAnnounceEvent(this, activity.getActor(), objectObject)); + return new ResponseEntity<>(CommandResult.fromString("Undo like/announce request accepted"), HttpStatus.OK); + } + } + if (activity instanceof Create) { + if (activity.getObject() instanceof Map) { + Map note = (Map) activity.getObject(); + if (note.get("type").equals("Note")) { + URI noteId = URI.create((String) note.get("id")); + if (messagesService.replyExists(noteId)) { + return new ResponseEntity<>(CommandResult.fromString("Reply already exists"), HttpStatus.OK); + } else { + String inReplyTo = (String) note.get("inReplyTo"); + if (StringUtils.isNotBlank(inReplyTo)) { + if (inReplyTo.startsWith(baseUri)) { + String postId = activityPubManager.postId(inReplyTo); + User user = new User(); + user.setUri(URI.create(activity.getActor())); + String markdown = remarkConverter.convertFragment((String) note.get("content")); + String commandBody = note.get("attachment") == null ? markdown : + ((List) note.get("attachment")).stream().map(attachmentObj -> { + Map attachment = (Map) attachmentObj; + String attachmentUrl = attachment.get("url"); + String attachmentName = attachment.get("name"); + return PlainTextFormatter.markdownUrl(attachmentUrl, attachmentName); + }).reduce(markdown, (currentUrl, nextUrl) -> String.format("%s\n%s", currentUrl, nextUrl)); + + CommandResult result = commandsManager.processCommand( + user, String.format("#%s %s", postId, commandBody), + URI.create(StringUtils.EMPTY)); + logger.info(jsonMapper.writeValueAsString(result)); + if (result.getNewMessage().isPresent()) { + messagesService.updateReplyUri(result.getNewMessage().get(), noteId); + return new ResponseEntity<>(result, HttpStatus.OK); + } else { + return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST); + } + } else { + Message reply = messagesService.getReplyByUri(inReplyTo); + if (reply != null) { + User user = new User(); + user.setUri(URI.create(activity.getActor())); + String markdown = remarkConverter.convertFragment((String)note.get("content")); + // combine note text with attachment urls + String commandBody = note.get("attachment") == null ? markdown : + ((List) note.get("attachment")).stream().map(attachmentObj -> { + Map attachment = (Map) attachmentObj; + String attachmentUrl = attachment.get("url"); + String attachmentName = attachment.get("name"); + return PlainTextFormatter.markdownUrl(attachmentUrl, attachmentName); + }).reduce(markdown, (currentUrl, nextUrl) -> String.format("%s\n%s", currentUrl, nextUrl)); + CommandResult result = commandsManager.processCommand( + user, + String.format("#%d/%d %s", reply.getMid(), reply.getRid(), commandBody), + URI.create(StringUtils.EMPTY)); + logger.info(jsonMapper.writeValueAsString(result)); + if (result.getNewMessage().isPresent()) { + messagesService.updateReplyUri(result.getNewMessage().get(), noteId); + return new ResponseEntity<>(result, HttpStatus.OK); + } else { + return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST); + } + } + } + } + } + } + } + } + if (activity instanceof Delete) { + if (activity.getObject() instanceof String) { + // Delete gone user + // TODO: check if it is really deleted and remove copy-paste + if (activity.getActor().equals(activity.getObject())) { + return new ResponseEntity<>(CommandResult.fromString("Delete request accepted"), HttpStatus.ACCEPTED); + } + } + Map tombstone = (Map) activity.getObject(); + if (tombstone.get("type").equals("Tombstone")) { + URI actor = URI.create(activity.getActor()); + URI reply = URI.create((String)tombstone.get("id")); + messagesService.deleteReply(actor, reply); + return new ResponseEntity<>(CommandResult.fromString("Delete request accepted"), HttpStatus.OK); + } + } + if (activity instanceof Like || activity instanceof Announce) { + String messageUri = activity.getObject() instanceof String ? (String) activity.getObject() + : activity.getObject() instanceof Context ? ((Context) activity.getObject()).getId() + : (String) ((Map)activity.getObject()).get("id"); + applicationEventPublisher.publishEvent(new AnnounceEvent(this, activity.getActor(), messageUri)); + return new ResponseEntity<>(CommandResult.fromString("Like/announce request accepted"), HttpStatus.OK); + } + logger.warn("Unknown activity: {}", jsonMapper.writeValueAsString(activity)); + return new ResponseEntity<>(CommandResult.fromString("Unknown activity"), HttpStatus.NOT_IMPLEMENTED); + } + if (activity instanceof Delete) { + if (activity.getObject() instanceof String) { + // Delete gone user + if (activity.getActor().equals(activity.getObject())) { + return new ResponseEntity<>(CommandResult.fromString("Delete request accepted"), HttpStatus.ACCEPTED); + } + } + } + return new ResponseEntity<>(CommandResult.fromString("Can not authenticate"), HttpStatus.UNAUTHORIZED); + } + @PostMapping(value = "/u/", produces = MediaType.APPLICATION_JSON_VALUE) + public User fetchUser(@RequestParam URI uri) { + return activityPubManager.personToUser(uri); + } +} diff --git a/src/main/java/com/juick/www/api/activity/helpers/ActivityIdDeserializer.java b/src/main/java/com/juick/www/api/activity/helpers/ActivityIdDeserializer.java new file mode 100644 index 00000000..e349bff7 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/helpers/ActivityIdDeserializer.java @@ -0,0 +1,38 @@ +/* + * 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 . + */ + +package com.juick.www.api.activity.helpers; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; + +import java.io.IOException; + +public class ActivityIdDeserializer extends JsonDeserializer { + @Override + public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + JsonToken jsonToken = p.getCurrentToken(); + if (jsonToken == JsonToken.START_OBJECT) { + JsonNode node = p.getCodec().readTree(p); + return node.get("id").textValue(); + } + return p.getValueAsString(); + } +} diff --git a/src/main/java/com/juick/www/api/activity/helpers/LinkValueDeserializer.java b/src/main/java/com/juick/www/api/activity/helpers/LinkValueDeserializer.java new file mode 100644 index 00000000..ab797f6c --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/helpers/LinkValueDeserializer.java @@ -0,0 +1,38 @@ +/* + * 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 . + */ + +package com.juick.www.api.activity.helpers; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; + +import java.io.IOException; + +public class LinkValueDeserializer extends JsonDeserializer { + @Override + public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + JsonToken jsonToken = p.getCurrentToken(); + if (jsonToken == JsonToken.VALUE_STRING) { + return p.getValueAsString(); + } + JsonNode node = p.getCodec().readTree(p); + return node.get("href").textValue(); + } +} diff --git a/src/main/java/com/juick/www/api/activity/model/Activity.java b/src/main/java/com/juick/www/api/activity/model/Activity.java new file mode 100644 index 00000000..2ac22349 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/Activity.java @@ -0,0 +1,50 @@ +/* + * 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 . + */ + +package com.juick.www.api.activity.model; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.juick.www.api.activity.helpers.ActivityIdDeserializer; +import org.apache.commons.lang3.StringUtils; + +import java.util.UUID; + +public abstract class Activity extends Context { + + @JsonDeserialize(using = ActivityIdDeserializer.class) + private String actor; + private Object object; + + public String getActor() { + return actor; + } + + public void setActor(String actor) { + this.actor = actor; + if (StringUtils.isEmpty(getId())) { + setId(String.format("%s#%s", this.actor, UUID.randomUUID().toString())); + } + } + + public Object getObject() { + return object; + } + + public void setObject(Object object) { + this.object = object; + } +} diff --git a/src/main/java/com/juick/www/api/activity/model/Context.java b/src/main/java/com/juick/www/api/activity/model/Context.java new file mode 100644 index 00000000..57e29e0f --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/Context.java @@ -0,0 +1,144 @@ +/* + * 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 . + */ + +package com.juick.www.api.activity.model; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.juick.www.api.activity.helpers.LinkValueDeserializer; +import com.juick.www.api.activity.model.activities.*; +import com.juick.www.api.activity.model.objects.*; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@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"), + @JsonSubTypes.Type(value = Undo.class, name = "Undo"), + @JsonSubTypes.Type(value = Like.class, name = "Like"), + @JsonSubTypes.Type(value = Block.class, name = "Block"), + @JsonSubTypes.Type(value = Announce.class, name = "Announce"), + @JsonSubTypes.Type(value = Activity.class, name = "Activity"), + @JsonSubTypes.Type(value = Image.class, name = "Image"), + @JsonSubTypes.Type(value = Key.class, name = "Key"), + @JsonSubTypes.Type(value = Link.class, name = "Link"), + @JsonSubTypes.Type(value = Hashtag.class, name = "Hashtag"), + @JsonSubTypes.Type(value = Mention.class, name = "Mention"), + @JsonSubTypes.Type(value = Emoji.class, name = "Emoji"), + @JsonSubTypes.Type(value = Note.class, name = "Note"), + @JsonSubTypes.Type(value = OrderedCollection.class, name = "OrderedCollection"), + @JsonSubTypes.Type(value = OrderedCollectionPage.class, name = "OrderedCollectionPage"), + @JsonSubTypes.Type(value = Person.class, name = "Person") +}) +public abstract class Context { + + private List context; + + private String id; + + private String name; + + private Instant published; + + @JsonDeserialize(using = LinkValueDeserializer.class) + private String url; + + private List to; + + private List tags; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getType() { + return getClass().getSimpleName(); + } + + @JsonProperty("@context") + @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) + public List getContext() { + return context; + } + + public final static String ACTIVITY_STREAMS_URI = "https://www.w3.org/ns/activitystreams"; + public final static String SECURITY_URI = "https://w3id.org/security/v1"; + public final static String LD_JSON_MEDIA_TYPE = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""; + public final static String ACTIVITY_MEDIA_TYPE = "application/activity+json"; + public final static String ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE = ACTIVITY_MEDIA_TYPE + "; profile=\"https://www.w3.org/ns/activitystreams\""; + public final static String ACTIVITYSTREAMS_PUBLIC = "https://www.w3.org/ns/activitystreams#Public"; + + public Instant getPublished() { + return published; + } + + public void setPublished(Instant published) { + this.published = published; + } + + public List getTo() { + return to; + } + + public void setTo(List to) { + this.to = to; + } + + public static Context build(Context response) { + response.context = new ArrayList<>(Arrays.asList(ACTIVITY_STREAMS_URI, SECURITY_URI)); + response.context.add(Collections.singletonMap("Hashtag", "as:Hashtag")); + return response; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + @JsonProperty("tag") + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags = tags; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/juick/www/api/activity/model/activities/Accept.java b/src/main/java/com/juick/www/api/activity/model/activities/Accept.java new file mode 100644 index 00000000..30a55839 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/activities/Accept.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 . + */ + +package com.juick.www.api.activity.model.activities; + +import com.juick.www.api.activity.model.Activity; + +public class Accept extends Activity { +} diff --git a/src/main/java/com/juick/www/api/activity/model/activities/Announce.java b/src/main/java/com/juick/www/api/activity/model/activities/Announce.java new file mode 100644 index 00000000..4561b10e --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/activities/Announce.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 . + */ + +package com.juick.www.api.activity.model.activities; + +import com.juick.www.api.activity.model.Activity; + +public class Announce extends Activity { +} diff --git a/src/main/java/com/juick/www/api/activity/model/activities/Block.java b/src/main/java/com/juick/www/api/activity/model/activities/Block.java new file mode 100644 index 00000000..66919235 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/activities/Block.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 . + */ + +package com.juick.www.api.activity.model.activities; + +import com.juick.www.api.activity.model.Activity; + +public class Block extends Activity { +} diff --git a/src/main/java/com/juick/www/api/activity/model/activities/Create.java b/src/main/java/com/juick/www/api/activity/model/activities/Create.java new file mode 100644 index 00000000..5da46545 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/activities/Create.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 . + */ + +package com.juick.www.api.activity.model.activities; + +import com.juick.www.api.activity.model.Activity; + +public class Create extends Activity { +} diff --git a/src/main/java/com/juick/www/api/activity/model/activities/Delete.java b/src/main/java/com/juick/www/api/activity/model/activities/Delete.java new file mode 100644 index 00000000..0214f869 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/activities/Delete.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 . + */ + +package com.juick.www.api.activity.model.activities; + +import com.juick.www.api.activity.model.Activity; + +public class Delete extends Activity { +} diff --git a/src/main/java/com/juick/www/api/activity/model/activities/Follow.java b/src/main/java/com/juick/www/api/activity/model/activities/Follow.java new file mode 100644 index 00000000..b7653d23 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/activities/Follow.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 . + */ + +package com.juick.www.api.activity.model.activities; + +import com.juick.www.api.activity.model.Activity; + +public class Follow extends Activity { +} diff --git a/src/main/java/com/juick/www/api/activity/model/activities/Like.java b/src/main/java/com/juick/www/api/activity/model/activities/Like.java new file mode 100644 index 00000000..76a35a3c --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/activities/Like.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 . + */ + +package com.juick.www.api.activity.model.activities; + +import com.juick.www.api.activity.model.Activity; + +public class Like extends Activity { +} diff --git a/src/main/java/com/juick/www/api/activity/model/activities/Undo.java b/src/main/java/com/juick/www/api/activity/model/activities/Undo.java new file mode 100644 index 00000000..0e1c7e8a --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/activities/Undo.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 . + */ + +package com.juick.www.api.activity.model.activities; + +import com.juick.www.api.activity.model.Activity; + +public class Undo extends Activity { +} diff --git a/src/main/java/com/juick/www/api/activity/model/activities/Update.java b/src/main/java/com/juick/www/api/activity/model/activities/Update.java new file mode 100644 index 00000000..d6ca9c1b --- /dev/null +++ b/src/main/java/com/juick/www/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 . + */ + +package com.juick.www.api.activity.model.activities; + +import com.juick.www.api.activity.model.Activity; + +public class Update extends Activity { +} diff --git a/src/main/java/com/juick/www/api/activity/model/objects/Emoji.java b/src/main/java/com/juick/www/api/activity/model/objects/Emoji.java new file mode 100644 index 00000000..bb556292 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/objects/Emoji.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 . + */ + +package com.juick.www.api.activity.model.objects; + +import com.juick.www.api.activity.model.Context; + +public class Emoji extends Context { +} diff --git a/src/main/java/com/juick/www/api/activity/model/objects/Hashtag.java b/src/main/java/com/juick/www/api/activity/model/objects/Hashtag.java new file mode 100644 index 00000000..175cc305 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/objects/Hashtag.java @@ -0,0 +1,28 @@ +/* + * 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 . + */ + +package com.juick.www.api.activity.model.objects; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Hashtag extends Mention { + @JsonCreator + public Hashtag(@JsonProperty("href") String href, @JsonProperty("name") String name) { + super(href, name); + } +} diff --git a/src/main/java/com/juick/www/api/activity/model/objects/Image.java b/src/main/java/com/juick/www/api/activity/model/objects/Image.java new file mode 100644 index 00000000..0dfa6271 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/objects/Image.java @@ -0,0 +1,32 @@ +/* + * 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 . + */ + +package com.juick.www.api.activity.model.objects; + +import com.juick.www.api.activity.model.Context; + +public class Image extends Context { + private String mediaType; + + public String getMediaType() { + return mediaType; + } + + public void setMediaType(String mediaType) { + this.mediaType = mediaType; + } +} diff --git a/src/main/java/com/juick/www/api/activity/model/objects/Key.java b/src/main/java/com/juick/www/api/activity/model/objects/Key.java new file mode 100644 index 00000000..26d60213 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/objects/Key.java @@ -0,0 +1,41 @@ +/* + * 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 . + */ + +package com.juick.www.api.activity.model.objects; + +import com.juick.www.api.activity.model.Context; + +public class Key extends Context { + private String owner; + private String publicKeyPem; + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public String getPublicKeyPem() { + return publicKeyPem; + } + + public void setPublicKeyPem(String publicKeyPem) { + this.publicKeyPem = publicKeyPem; + } +} diff --git a/src/main/java/com/juick/www/api/activity/model/objects/Link.java b/src/main/java/com/juick/www/api/activity/model/objects/Link.java new file mode 100644 index 00000000..58bf2304 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/objects/Link.java @@ -0,0 +1,32 @@ +/* + * 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 . + */ + +package com.juick.www.api.activity.model.objects; + +import com.juick.www.api.activity.model.Context; + +public class Link extends Context { + private String href; + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } +} diff --git a/src/main/java/com/juick/www/api/activity/model/objects/Mention.java b/src/main/java/com/juick/www/api/activity/model/objects/Mention.java new file mode 100644 index 00000000..a6099b53 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/objects/Mention.java @@ -0,0 +1,29 @@ +/* + * 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 . + */ + +package com.juick.www.api.activity.model.objects; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Mention extends Link { + @JsonCreator + public Mention(@JsonProperty("href") String href, @JsonProperty("name") String name) { + this.setHref(href); + this.setName(name); + } +} diff --git a/src/main/java/com/juick/www/api/activity/model/objects/Note.java b/src/main/java/com/juick/www/api/activity/model/objects/Note.java new file mode 100644 index 00000000..b04b1ec9 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/objects/Note.java @@ -0,0 +1,81 @@ +/* + * 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 . + */ + +package com.juick.www.api.activity.model.objects; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.juick.www.api.activity.model.Context; + +import java.util.List; + +public class Note extends Context { + private String content; + private String attributedTo; + private String inReplyTo; + private List attachment; + private List to; + private List cc; + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getAttributedTo() { + return attributedTo; + } + + public void setAttributedTo(String attributedTo) { + this.attributedTo = attributedTo; + } + + @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) + public List getAttachment() { + return attachment; + } + + public void setAttachment(List attachment) { + this.attachment = attachment; + } + + public List getTo() { + return to; + } + + public void setTo(List to) { + this.to = to; + } + + public List getCc() { + return cc; + } + + public void setCc(List cc) { + this.cc = cc; + } + + public String getInReplyTo() { + return inReplyTo; + } + + public void setInReplyTo(String inReplyTo) { + this.inReplyTo = inReplyTo; + } +} diff --git a/src/main/java/com/juick/www/api/activity/model/objects/OrderedCollection.java b/src/main/java/com/juick/www/api/activity/model/objects/OrderedCollection.java new file mode 100644 index 00000000..d7d43a26 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/objects/OrderedCollection.java @@ -0,0 +1,42 @@ +/* + * 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 . + */ + +package com.juick.www.api.activity.model.objects; + +import com.juick.www.api.activity.model.Context; + +public class OrderedCollection extends Context { + + private int totalItems; + + public int getTotalItems() { + return totalItems; + } + + public void setTotalItems(int totalItems) { + this.totalItems = totalItems; + } + private String first; + + public String getFirst() { + return first; + } + + public void setFirst(String first) { + this.first = first; + } +} diff --git a/src/main/java/com/juick/www/api/activity/model/objects/OrderedCollectionPage.java b/src/main/java/com/juick/www/api/activity/model/objects/OrderedCollectionPage.java new file mode 100644 index 00000000..340e24cf --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/objects/OrderedCollectionPage.java @@ -0,0 +1,75 @@ +/* + * 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 . + */ + +package com.juick.www.api.activity.model.objects; + +import com.juick.www.api.activity.model.Context; + +import java.util.List; + +public class OrderedCollectionPage extends Context { + + private String partOf; + + private String first; + + private String next; + + private String last; + + private List orderedItems; + + public String getNext() { + return next; + } + + public void setNext(String next) { + this.next = next; + } + + public List getOrderedItems() { + return orderedItems; + } + + public void setOrderedItems(List orderedItems) { + this.orderedItems = orderedItems; + } + + public String getPartOf() { + return partOf; + } + + public void setPartOf(String partOf) { + this.partOf = partOf; + } + + public String getFirst() { + return first; + } + + public void setFirst(String first) { + this.first = first; + } + + public String getLast() { + return last; + } + + public void setLast(String last) { + this.last = last; + } +} diff --git a/src/main/java/com/juick/www/api/activity/model/objects/Person.java b/src/main/java/com/juick/www/api/activity/model/objects/Person.java new file mode 100644 index 00000000..c653bee1 --- /dev/null +++ b/src/main/java/com/juick/www/api/activity/model/objects/Person.java @@ -0,0 +1,104 @@ +/* + * 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 . + */ + +package com.juick.www.api.activity.model.objects; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.juick.www.api.activity.model.Context; + +public class Person extends Context { + + private String name; + private String preferredUsername; + private Image icon; + private String inbox; + private String outbox; + private String following; + private String followers; + private Key publicKey; + + @Override + public String getType() { + return "Person"; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @JsonTypeInfo(use = JsonTypeInfo.Id.NONE) + public Image getIcon() { + return icon; + } + + public void setIcon(Image icon) { + this.icon = icon; + } + + public String getOutbox() { + return outbox; + } + + public void setOutbox(String outbox) { + this.outbox = outbox; + } + + public String getInbox() { + return inbox; + } + + public void setInbox(String inbox) { + this.inbox = inbox; + } + + public String getFollowing() { + return following; + } + + public void setFollowing(String following) { + this.following = following; + } + + public String getFollowers() { + return followers; + } + + public void setFollowers(String followers) { + this.followers = followers; + } + + @JsonTypeInfo(use = JsonTypeInfo.Id.NONE) + public Key getPublicKey() { + return publicKey; + } + + public void setPublicKey(Key publicKey) { + this.publicKey = publicKey; + } + + public String getPreferredUsername() { + return preferredUsername; + } + + public void setPreferredUsername(String preferredUsername) { + this.preferredUsername = preferredUsername; + } +} -- cgit v1.2.3