package com.juick.server.api.activity; import com.juick.User; import com.juick.server.KeystoreManager; import com.juick.server.api.activity.model.*; 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.util.MessageUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; 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.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @RestController public class Profile { @Inject private UserService userService; @Inject private MessagesService messagesService; @Inject private KeystoreManager keystoreManager; @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; @GetMapping(value = "/api/u/{userName}", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_MEDIA_TYPE }) public Person getUser(@PathVariable String userName) { User user = userService.getUserByName(userName); if (!user.isAnonymous()) { UriComponentsBuilder uri = UriComponentsBuilder.fromUriString(baseUri); Person person = new Person(); uri.replacePath(String.format("/u/%s", userName)); person.setId(uri.toUriString()); person.setName(userName); Key publicKey = new Key(); publicKey.setId(person.getId() + "#main-key"); publicKey.setOwner(person.getId()); publicKey.setPublicKeyPem(keystoreManager.getPublicKey()); person.setPublicKey(publicKey); uri.replacePath("/post"); person.setInbox(uri.toUriString()); person.setOutbox(uri.replacePath(String.format("/u/%s/blog/toc", userName)).toUriString()); person.setFollowers(uri.replacePath(String.format("/u/%s/followers/toc", userName)).toUriString()); person.setFollowing(uri.replacePath(String.format("/u/%s/following/toc", userName)).toUriString()); 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; } throw new HttpNotFoundException(); } @GetMapping(value = "/api/u/{userName}/blog/toc", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_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 blog; } throw new HttpNotFoundException(); } @GetMapping(value = "/api/u/{userName}/blog", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_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(); String followersUri = uri.replacePath(String.format("/u/%s/followers/toc", userName)).toUriString(); List mids = messagesService.getUserBlog(user.getUid(), 0, before); List notes = messagesService.getMessages(visitor, mids).stream().map(m -> { Note note = new Note(); note.setId(uri.replacePath(String.format("/m/%d", m.getMid())).toUriString()); note.setAttributedTo(personUri); note.setTo(Arrays.asList(followersUri, "https://www.w3.org/ns/activitystreams#Public")); note.setPublished(m.getTimestamp()); note.setContent(MessageUtils.formatMessage(m.getText())); if (StringUtils.isNotBlank(m.getAttachmentType())) { Link attachment = new Link(); attachment.setHref(m.getAttachment().getMedium().getUrl()); note.setAttachment(attachment); } return note; }).collect(Collectors.toList()); Person person = new Person(); person.setName(user.getName()); 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()); } return page; } throw new HttpNotFoundException(); } @GetMapping(value = "/api/u/{userName}/followers/toc", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_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 followers; } throw new HttpNotFoundException(); } @GetMapping(value = "/api/u/{userName}/followers", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_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); Person person = new Person(); person.setName(user.getName()); OrderedCollectionPage result = new OrderedCollectionPage(); result.setId(ServletUriComponentsBuilder.fromCurrentRequestUri().toUriString()); result.setOrderedItems(followersPage.map(a -> { Person follower = new Person(); follower.setName(a.getName()); Link url = new Link(); url.setHref(uriComponentsBuilder.replacePath(String.format("/u/%s", a.getName())).toUriString()); follower.setUrl(url); return follower; }).collect(Collectors.toList())); boolean hasNext = followers.size() <= 20 * page; if (hasNext) { result.setNext(uriComponentsBuilder.queryParam("page", page + 1).toUriString()); } return result; } throw new HttpNotFoundException(); } @GetMapping(value = "/api/u/{userName}/following/toc", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_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 following; } throw new HttpNotFoundException(); } @GetMapping(value = "/api/u/{userName}/following", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_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); Person person = new Person(); person.setName(user.getName()); OrderedCollectionPage result = new OrderedCollectionPage(); result.setId(ServletUriComponentsBuilder.fromCurrentRequestUri().toUriString()); result.setOrderedItems(followingPage.map(a -> { Person follower = new Person(); follower.setName(a.getName()); Link url = new Link(); url.setHref(uriComponentsBuilder.replacePath(String.format("/u/%s", a.getName())).toUriString()); follower.setUrl(url); return follower; }).collect(Collectors.toList())); boolean hasNext = following.size() <= 20 * page; if (hasNext) { result.setNext(uriComponentsBuilder.queryParam("page", page + 1).toUriString()); } return result; } throw new HttpNotFoundException(); } }