From 7aaa3f9a29c280f01c677c918932620be45cdbd7 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Thu, 8 Nov 2018 21:38:27 +0300 Subject: Merge everything into single Spring Boot application --- .../com/juick/server/api/activity/Profile.java | 379 +++++++++++++++++++++ .../juick/server/api/activity/model/Activity.java | 23 ++ .../juick/server/api/activity/model/Context.java | 123 +++++++ .../api/activity/model/activities/Accept.java | 6 + .../api/activity/model/activities/Announce.java | 6 + .../api/activity/model/activities/Block.java | 6 + .../api/activity/model/activities/Create.java | 6 + .../api/activity/model/activities/Delete.java | 6 + .../api/activity/model/activities/Follow.java | 6 + .../server/api/activity/model/activities/Like.java | 6 + .../server/api/activity/model/activities/Undo.java | 6 + .../server/api/activity/model/objects/Hashtag.java | 6 + .../server/api/activity/model/objects/Image.java | 15 + .../server/api/activity/model/objects/Key.java | 24 ++ .../server/api/activity/model/objects/Link.java | 15 + .../server/api/activity/model/objects/Mention.java | 12 + .../server/api/activity/model/objects/Note.java | 64 ++++ .../activity/model/objects/OrderedCollection.java | 25 ++ .../model/objects/OrderedCollectionPage.java | 58 ++++ .../server/api/activity/model/objects/Person.java | 87 +++++ 20 files changed, 879 insertions(+) create mode 100644 src/main/java/com/juick/server/api/activity/Profile.java create mode 100644 src/main/java/com/juick/server/api/activity/model/Activity.java create mode 100644 src/main/java/com/juick/server/api/activity/model/Context.java create mode 100644 src/main/java/com/juick/server/api/activity/model/activities/Accept.java create mode 100644 src/main/java/com/juick/server/api/activity/model/activities/Announce.java create mode 100644 src/main/java/com/juick/server/api/activity/model/activities/Block.java create mode 100644 src/main/java/com/juick/server/api/activity/model/activities/Create.java create mode 100644 src/main/java/com/juick/server/api/activity/model/activities/Delete.java create mode 100644 src/main/java/com/juick/server/api/activity/model/activities/Follow.java create mode 100644 src/main/java/com/juick/server/api/activity/model/activities/Like.java create mode 100644 src/main/java/com/juick/server/api/activity/model/activities/Undo.java create mode 100644 src/main/java/com/juick/server/api/activity/model/objects/Hashtag.java create mode 100644 src/main/java/com/juick/server/api/activity/model/objects/Image.java create mode 100644 src/main/java/com/juick/server/api/activity/model/objects/Key.java create mode 100644 src/main/java/com/juick/server/api/activity/model/objects/Link.java create mode 100644 src/main/java/com/juick/server/api/activity/model/objects/Mention.java create mode 100644 src/main/java/com/juick/server/api/activity/model/objects/Note.java create mode 100644 src/main/java/com/juick/server/api/activity/model/objects/OrderedCollection.java create mode 100644 src/main/java/com/juick/server/api/activity/model/objects/OrderedCollectionPage.java create mode 100644 src/main/java/com/juick/server/api/activity/model/objects/Person.java (limited to 'src/main/java/com/juick/server/api/activity') diff --git a/src/main/java/com/juick/server/api/activity/Profile.java b/src/main/java/com/juick/server/api/activity/Profile.java new file mode 100644 index 00000000..10390ea1 --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/Profile.java @@ -0,0 +1,379 @@ +package com.juick.server.api.activity; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.juick.Message; +import com.juick.User; +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.server.api.activity.model.Activity; +import com.juick.server.api.activity.model.Context; +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.Follow; +import com.juick.server.api.activity.model.activities.Undo; +import com.juick.server.api.activity.model.objects.Image; +import com.juick.server.api.activity.model.objects.Key; +import com.juick.server.api.activity.model.objects.Note; +import com.juick.server.api.activity.model.objects.OrderedCollection; +import com.juick.server.api.activity.model.objects.OrderedCollectionPage; +import com.juick.server.api.activity.model.objects.Person; +import com.juick.server.util.HttpBadRequestException; +import com.juick.server.util.HttpNotFoundException; +import com.juick.server.util.UserUtils; +import com.juick.service.MessagesService; +import com.juick.service.UserService; +import com.juick.service.activities.DeleteUserEvent; +import com.juick.service.activities.FollowEvent; +import com.juick.service.activities.UndoFollowEvent; +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.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +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.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import javax.inject.Inject; +import java.net.URI; +import java.util.HashMap; +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(Profile.class); + @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; + @Value("${img_url:http://localhost:8080/i/}") + private String baseImagesUri; + @Inject + private ObjectMapper jsonMapper; + + @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)); + UriComponentsBuilder image = UriComponentsBuilder.fromUriString(baseImagesUri); + image.path(String.format("/a/%d.png", user.getUid())); + Image avatar = new Image(); + avatar.setUrl(image.toUriString()); + 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(@PathVariable String userName, + @RequestParam(required = false, defaultValue = "0") int before) { + User visitor = UserUtils.getCurrentUser(); + User user = userService.getUserByName(userName); + if (!user.isAnonymous()) { + 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))); + } + + @PostMapping(value = "/api/inbox", consumes = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE}) + public ResponseEntity processInbox(@RequestBody Activity activity, + @RequestHeader(name = "Host") String host, + @RequestHeader(name = "Date") String date, + @RequestHeader(name = "Digest", required = false) String digest, + @RequestHeader(name = "Content-Type") String contentType, + @RequestHeader(name = "User-Agent", required = false) String userAgent, + @RequestHeader(name = "Accept-Encoding", required = false) String acceptEncoding, + @RequestHeader(name = "Signature", required = false) String signature) throws Exception { + UriComponents componentsBuilder = ServletUriComponentsBuilder.fromCurrentRequestUri().build(); + Map headers = new HashMap<>(); + headers.put("host", host.split(":", 2)[0]); + headers.put("date", date); + headers.put("digest", digest); + headers.put("content-type", contentType); + headers.put("user-agent", userAgent); + headers.put("accept-encoding", acceptEncoding); + boolean valid = signatureManager.verifySignature(signature, URI.create(activity.getActor()), "POST", + componentsBuilder.getPath(), headers); + if (valid) { + if (activity instanceof Follow) { + Follow followRequest = (Follow) activity; + String actor = followRequest.getActor(); + Person follower = (Person) signatureManager.getContext(URI.create(actor)).orElseThrow(HttpBadRequestException::new); + applicationEventPublisher.publishEvent( + new FollowEvent(this, followRequest)); + return new ResponseEntity<>(HttpStatus.ACCEPTED); + + } + if (activity instanceof Undo) { + String follower = (String) ((Map) activity.getObject()).get("object"); + applicationEventPublisher.publishEvent(new UndoFollowEvent(this, activity.getActor(), follower)); + return new ResponseEntity<>(HttpStatus.OK); + } + if (activity instanceof Delete) { + if (activity.getObject() instanceof String) { + // Delete user + applicationEventPublisher.publishEvent(new DeleteUserEvent(this, (String)activity.getObject())); + return new ResponseEntity<>(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<>(HttpStatus.OK); + } else { + String inReplyTo = (String) note.get("inReplyTo"); + if (StringUtils.isNotBlank(inReplyTo)) { + if (inReplyTo.startsWith(baseUri)) { + UriComponents uri = UriComponentsBuilder.fromUriString(inReplyTo).build(); + String postId = uri.getPath().substring(uri.getPath().lastIndexOf('/') + 1).replace("-", "/"); + User user = new User(); + user.setUri(URI.create(activity.getActor())); + String attachment = StringUtils.EMPTY; + if (note.get("attachment") != null && ((List) note.get("attachment")).size() > 0) { + Map attachmentObj = (Map) ((List) note.get("attachment")).get(0); + attachment = (String) attachmentObj.get("url"); + } + CommandResult result = commandsManager.processCommand(user, String.format("#%s %s", postId, note.get("content")), URI.create(attachment)); + logger.info(jsonMapper.writeValueAsString(result)); + if (result.getNewMessage().isPresent()) { + messagesService.updateReplyUri(result.getNewMessage().get(), noteId); + return new ResponseEntity<>(HttpStatus.OK); + } else { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } else { + Message reply = messagesService.getReplyByUri(inReplyTo); + if (reply != null) { + User user = new User(); + user.setUri(URI.create(activity.getActor())); + String attachment = StringUtils.EMPTY; + if (note.get("attachment") != null && ((List) note.get("attachment")).size() > 0) { + Map attachmentObj = (Map) ((List) note.get("attachment")).get(0); + attachment = (String) attachmentObj.get("url"); + } + CommandResult result = commandsManager.processCommand(user, String.format("#%d/%d %s", reply.getMid(), reply.getRid(), note.get("content")), URI.create(attachment)); + logger.info(jsonMapper.writeValueAsString(result)); + if (result.getNewMessage().isPresent()) { + messagesService.updateReplyUri(result.getNewMessage().get(), noteId); + return new ResponseEntity<>(HttpStatus.OK); + } else { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } + } + } + } + } + } + } + if (activity instanceof Delete) { + 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<>(HttpStatus.OK); + } + } + if (activity instanceof Announce) { + logger.info("Announce: {}", jsonMapper.writeValueAsString(activity)); + return new ResponseEntity<>(HttpStatus.OK); + } + logger.warn("Unknown activity: {}", jsonMapper.writeValueAsString(activity)); + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } + return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); + } + @PostMapping(value = "/u/", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public User fetchUser(@RequestParam URI uri) { + Person person = (Person) signatureManager.getContext(uri).orElseThrow(HttpBadRequestException::new); + User user = new User(); + user.setUri(URI.create(person.getUrl())); + user.setName(person.getPreferredUsername()); + if (person.getIcon() != null) { + user.setAvatar(person.getIcon().getUrl()); + } + return user; + } +} diff --git a/src/main/java/com/juick/server/api/activity/model/Activity.java b/src/main/java/com/juick/server/api/activity/model/Activity.java new file mode 100644 index 00000000..ec126b88 --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/Activity.java @@ -0,0 +1,23 @@ +package com.juick.server.api.activity.model; + +public abstract class Activity extends Context { + + private String actor; + private Object object; + + public String getActor() { + return actor; + } + + public void setActor(String actor) { + this.actor = actor; + } + + public Object getObject() { + return object; + } + + public void setObject(Object object) { + this.object = object; + } +} 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 new file mode 100644 index 00000000..0df8f8c7 --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/Context.java @@ -0,0 +1,123 @@ +package com.juick.server.api.activity.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.juick.server.api.activity.model.activities.*; +import com.juick.server.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 = 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 = 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; + + 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") + 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 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/server/api/activity/model/activities/Accept.java b/src/main/java/com/juick/server/api/activity/model/activities/Accept.java new file mode 100644 index 00000000..1e0a9968 --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/activities/Accept.java @@ -0,0 +1,6 @@ +package com.juick.server.api.activity.model.activities; + +import com.juick.server.api.activity.model.Activity; + +public class Accept extends Activity { +} diff --git a/src/main/java/com/juick/server/api/activity/model/activities/Announce.java b/src/main/java/com/juick/server/api/activity/model/activities/Announce.java new file mode 100644 index 00000000..f2859404 --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/activities/Announce.java @@ -0,0 +1,6 @@ +package com.juick.server.api.activity.model.activities; + +import com.juick.server.api.activity.model.Activity; + +public class Announce extends Activity { +} diff --git a/src/main/java/com/juick/server/api/activity/model/activities/Block.java b/src/main/java/com/juick/server/api/activity/model/activities/Block.java new file mode 100644 index 00000000..0e5a02d4 --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/activities/Block.java @@ -0,0 +1,6 @@ +package com.juick.server.api.activity.model.activities; + +import com.juick.server.api.activity.model.Activity; + +public class Block extends Activity { +} diff --git a/src/main/java/com/juick/server/api/activity/model/activities/Create.java b/src/main/java/com/juick/server/api/activity/model/activities/Create.java new file mode 100644 index 00000000..52507373 --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/activities/Create.java @@ -0,0 +1,6 @@ +package com.juick.server.api.activity.model.activities; + +import com.juick.server.api.activity.model.Activity; + +public class Create extends Activity { +} diff --git a/src/main/java/com/juick/server/api/activity/model/activities/Delete.java b/src/main/java/com/juick/server/api/activity/model/activities/Delete.java new file mode 100644 index 00000000..f4392020 --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/activities/Delete.java @@ -0,0 +1,6 @@ +package com.juick.server.api.activity.model.activities; + +import com.juick.server.api.activity.model.Activity; + +public class Delete extends Activity { +} diff --git a/src/main/java/com/juick/server/api/activity/model/activities/Follow.java b/src/main/java/com/juick/server/api/activity/model/activities/Follow.java new file mode 100644 index 00000000..573ecc6e --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/activities/Follow.java @@ -0,0 +1,6 @@ +package com.juick.server.api.activity.model.activities; + +import com.juick.server.api.activity.model.Activity; + +public class Follow extends Activity { +} diff --git a/src/main/java/com/juick/server/api/activity/model/activities/Like.java b/src/main/java/com/juick/server/api/activity/model/activities/Like.java new file mode 100644 index 00000000..3670293d --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/activities/Like.java @@ -0,0 +1,6 @@ +package com.juick.server.api.activity.model.activities; + +import com.juick.server.api.activity.model.Activity; + +public class Like extends Activity { +} diff --git a/src/main/java/com/juick/server/api/activity/model/activities/Undo.java b/src/main/java/com/juick/server/api/activity/model/activities/Undo.java new file mode 100644 index 00000000..4e87e9d0 --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/activities/Undo.java @@ -0,0 +1,6 @@ +package com.juick.server.api.activity.model.activities; + +import com.juick.server.api.activity.model.Activity; + +public class Undo extends Activity { +} diff --git a/src/main/java/com/juick/server/api/activity/model/objects/Hashtag.java b/src/main/java/com/juick/server/api/activity/model/objects/Hashtag.java new file mode 100644 index 00000000..34e73be6 --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/objects/Hashtag.java @@ -0,0 +1,6 @@ +package com.juick.server.api.activity.model.objects; + +import com.juick.server.api.activity.model.Context; + +public class Hashtag extends Context { +} diff --git a/src/main/java/com/juick/server/api/activity/model/objects/Image.java b/src/main/java/com/juick/server/api/activity/model/objects/Image.java new file mode 100644 index 00000000..e067f729 --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/objects/Image.java @@ -0,0 +1,15 @@ +package com.juick.server.api.activity.model.objects; + +import com.juick.server.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/server/api/activity/model/objects/Key.java b/src/main/java/com/juick/server/api/activity/model/objects/Key.java new file mode 100644 index 00000000..075c51dd --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/objects/Key.java @@ -0,0 +1,24 @@ +package com.juick.server.api.activity.model.objects; + +import com.juick.server.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/server/api/activity/model/objects/Link.java b/src/main/java/com/juick/server/api/activity/model/objects/Link.java new file mode 100644 index 00000000..0c4f26dc --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/objects/Link.java @@ -0,0 +1,15 @@ +package com.juick.server.api.activity.model.objects; + +import com.juick.server.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/server/api/activity/model/objects/Mention.java b/src/main/java/com/juick/server/api/activity/model/objects/Mention.java new file mode 100644 index 00000000..bcb52d37 --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/objects/Mention.java @@ -0,0 +1,12 @@ +package com.juick.server.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/server/api/activity/model/objects/Note.java b/src/main/java/com/juick/server/api/activity/model/objects/Note.java new file mode 100644 index 00000000..baad2d3b --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/objects/Note.java @@ -0,0 +1,64 @@ +package com.juick.server.api.activity.model.objects; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.juick.server.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/server/api/activity/model/objects/OrderedCollection.java b/src/main/java/com/juick/server/api/activity/model/objects/OrderedCollection.java new file mode 100644 index 00000000..426cf331 --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/objects/OrderedCollection.java @@ -0,0 +1,25 @@ +package com.juick.server.api.activity.model.objects; + +import com.juick.server.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/server/api/activity/model/objects/OrderedCollectionPage.java b/src/main/java/com/juick/server/api/activity/model/objects/OrderedCollectionPage.java new file mode 100644 index 00000000..601919ba --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/objects/OrderedCollectionPage.java @@ -0,0 +1,58 @@ +package com.juick.server.api.activity.model.objects; + +import com.juick.server.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/server/api/activity/model/objects/Person.java b/src/main/java/com/juick/server/api/activity/model/objects/Person.java new file mode 100644 index 00000000..2d3a45d7 --- /dev/null +++ b/src/main/java/com/juick/server/api/activity/model/objects/Person.java @@ -0,0 +1,87 @@ +package com.juick.server.api.activity.model.objects; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.juick.server.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