/* * Copyright (C) 2008-2020, 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; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.inject.Inject; import com.juick.model.AnonymousUser; import com.juick.model.ApplicationStatus; import com.juick.model.User; import com.juick.service.EmailService; import com.juick.service.MessagesService; import com.juick.service.StorageService; import com.juick.service.TagService; import com.juick.service.TelegramService; import com.juick.service.UserService; import com.juick.service.activities.UpdateUserEvent; import com.juick.service.component.MailVerificationEvent; import com.juick.util.HttpBadRequestException; import com.juick.util.HttpNotFoundException; import com.juick.util.HttpUtils; import com.juick.util.WebUtils; import com.juick.www.WebApp; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; /** * @author ugnich */ @RestController public class Users { @Inject private UserService userService; @Inject private MessagesService messagesService; @Inject private TelegramService telegramService; @Inject private EmailService emailService; @Inject private TagService tagService; @Inject private WebApp webApp; @Inject private StorageService storageService; @Inject private ApplicationEventPublisher applicationEventPublisher; @RequestMapping(value = "/api/auth", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public String getAuthToken(@ModelAttribute User visitor) { return userService.getHashByUID(visitor.getUid()); } @RequestMapping(value = "/api/users", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public List doGetUsers( @ModelAttribute User visitor, @RequestParam(value = "uname", required = false) List unames) { List users = new ArrayList<>(); if (unames != null) { unames.removeIf(WebUtils::isNotUserName); if (!unames.isEmpty() && unames.size() < 20) users.addAll(userService.getUsersByName(unames)); } users.forEach(u -> u.setAvatar(webApp.getAvatarUrl(u))); if (!users.isEmpty()) return users; if (!visitor.isAnonymous()) { visitor.setAvatar(webApp.getAvatarUrl(visitor)); return Collections.singletonList(visitor); } throw new HttpNotFoundException(); } @GetMapping("/api/me") public SecureUser getMe(@ModelAttribute User visitor) { SecureUser me = new SecureUser(); me.setUid(visitor.getUid()); me.setName(visitor.getName()); me.setAuthHash(getAuthToken(visitor)); List unread = messagesService.getUnread(visitor); me.setUnread(unread); me.setUnreadCount(unread.size()); var friends = userService.getUserFriends(visitor.getUid()); friends.forEach(r -> r.setAvatar(webApp.getAvatarUrl(r))); me.setRead(friends); var readers = userService.getUserReaders(visitor.getUid()); readers.forEach(r -> r.setAvatar(webApp.getAvatarUrl(r))); me.setReaders(readers); me.setAvatar(webApp.getAvatarUrl(visitor)); me.getTagStats().addAll(tagService.getUserTagStats(me.getUid())); return (SecureUser)userService.getUserInfo(me); } @PostMapping("/api/me") public void updateMe(@ModelAttribute User visitor, @RequestParam(required = false) String password, @RequestParam(value = "jid-del", required = false) String jidForDeletion, @RequestParam(value = "email-add", required = false) String newEmail, @RequestParam(value = "email-del", required = false) String emailForDeletion, @RequestParam(value = "account-del", required = false) String accountToDelete) { if (StringUtils.isNotEmpty(password)) { if (!userService.updatePassword(visitor, password)) { throw new HttpBadRequestException(); } } if (StringUtils.isNotEmpty(jidForDeletion)) { if (!userService.deleteJID(visitor.getUid(), jidForDeletion)) { throw new HttpBadRequestException(); } } if (StringUtils.isNotEmpty(newEmail)) { if (!emailService.verifyAddressByCode(visitor.getUid(), newEmail)) { String authCode = RandomStringUtils.randomAlphanumeric(8).toUpperCase(); if (emailService.addVerificationCode(visitor.getUid(), newEmail, authCode)) { applicationEventPublisher.publishEvent(new MailVerificationEvent(this, newEmail , authCode)); } } } if (StringUtils.isNotEmpty(emailForDeletion)) { if (!emailService.deleteEmail(visitor.getUid(), emailForDeletion)) { throw new HttpBadRequestException(); } } if (StringUtils.isNotEmpty(accountToDelete)) { switch (accountToDelete) { case "twitter": userService.deleteTwitterToken(visitor.getUid()); break; case "vk": userService.deleteVKUser(visitor.getUid()); break; case "durov": telegramService.deleteTelegramUser(visitor.getUid()); break; } } } @PostMapping("/api/me/subscribe") public void subscribeMe(@ModelAttribute User visitor, String email) { // TODO: check status emailService.setNotificationsEmail(visitor.getUid(), email); } @PostMapping("/api/me/upload") public void updateInfo(@ModelAttribute User visitor, @RequestParam MultipartFile avatar) throws IOException { String avatarTmpPath = HttpUtils.receiveMultiPartFile(avatar, storageService.getTemporaryDirectory()).getHost(); if (StringUtils.isNotEmpty(avatarTmpPath)) { storageService.saveAvatar(avatarTmpPath, visitor); applicationEventPublisher.publishEvent(new UpdateUserEvent(this, visitor)); } } @RequestMapping(value = "/api/users/read", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public List doGetUserRead( @ModelAttribute User visitor, @RequestParam String uname) { int uid = 0; if (uname == null) { uid = visitor.getUid(); } else { if (WebUtils.isUserName(uname)) { User u = userService.getUserByName(uname); if (!u.isAnonymous()) { uid = u.getUid(); } } } if (uid > 0) { List friends = userService.getUserFriends(uid); friends.forEach(f -> f.setAvatar(webApp.getAvatarUrl(f))); return friends; } throw new HttpNotFoundException(); } @RequestMapping(value = "/api/users/readers", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public List doGetUserReaders( @ModelAttribute User visitor, @RequestParam String uname) { int uid = 0; if (uname == null) { uid = visitor.getUid(); } else { if (WebUtils.isUserName(uname)) { User u = userService.getUserByName(uname); if (!u.isAnonymous()) { uid = u.getUid(); } } } if (uid > 0) { List readers = userService.getUserReaders(uid); readers.forEach(r -> r.setAvatar(webApp.getAvatarUrl(r))); return readers; } throw new HttpNotFoundException(); } @GetMapping("/api/info/{uname}") public User getUserInfo(@ModelAttribute User visitor, @PathVariable String uname) { User user = userService.getUserByName(uname); if (!user.isBanned()) { user.setRead(doGetUserRead(visitor, uname)); user.setReaders(doGetUserReaders(visitor, uname)); user.setAvatar(webApp.getAvatarUrl(user)); return userService.getUserInfo(user); } throw new HttpNotFoundException(); } @Deprecated @GetMapping(value = "/api/avatar", produces = MediaType.IMAGE_PNG_VALUE) public byte[] getAvatarUrl( @RequestParam(required = false) String uname, @RequestParam(required = false) String jid) throws IOException { User user = AnonymousUser.INSTANCE; if (StringUtils.isNotEmpty(uname)) { user = userService.getUserByName(uname); } if (user.isAnonymous() && StringUtils.isNotEmpty(jid)) { user = userService.getUserByJID(jid); } return IOUtils.toByteArray(URI.create(webApp.getAvatarUrl(user))); } public class SecureUser extends User { public String getHash() { return getAuthHash(); } public List getJIDs() { return userService.getAllJIDs(this); } public List getEmails() { return userService.getEmails(this); } public String getActiveEmail() { return emailService.getNotificationsEmail(this.getUid()); } public String getTwitterName() { return userService.getTwitterName(this.getUid()); } public String getTelegramName() { return userService.getTelegramName(this.getUid()); } public ApplicationStatus getFacebookStatus() { return userService.getFbCrossPostStatus(this.getUid()); } } }