diff options
Diffstat (limited to 'src/main/java/com/juick/www/api/Users.java')
-rw-r--r-- | src/main/java/com/juick/www/api/Users.java | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/src/main/java/com/juick/www/api/Users.java b/src/main/java/com/juick/www/api/Users.java new file mode 100644 index 00000000..06467b7d --- /dev/null +++ b/src/main/java/com/juick/www/api/Users.java @@ -0,0 +1,279 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +package com.juick.www.api; + +import com.juick.model.User; +import com.juick.model.AnonymousUser; +import com.juick.model.ApplicationStatus; +import com.juick.server.util.HttpBadRequestException; +import com.juick.server.util.HttpNotFoundException; +import com.juick.server.util.HttpUtils; +import com.juick.server.util.WebUtils; +import com.juick.www.WebApp; +import com.juick.service.*; +import com.juick.service.component.MailVerificationEvent; +import com.juick.service.security.annotation.Visitor; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.inject.Inject; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author ugnich + */ +@RestController +public class Users { + @Inject + private UserService userService; + @Inject + private MessagesService messagesService; + @Inject + private CrosspostService crosspostService; + @Inject + private TelegramService telegramService; + @Inject + private EmailService emailService; + @Inject + private TagService tagService; + @Inject + private WebApp webApp; + @Inject + private ImagesService imagesService; + @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}") + private String tmpDir; + @Inject + private ApplicationEventPublisher applicationEventPublisher; + + @RequestMapping(value = "/api/auth", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public String getAuthToken(@Visitor User visitor) { + return userService.getHashByUID(visitor.getUid()); + } + + @RequestMapping(value = "/api/users", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public List<User> doGetUsers( + @Visitor User visitor, + @RequestParam(value = "uname", required = false) List<String> unames) { + List<User> 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(@Visitor User visitor) { + SecureUser me = new SecureUser(); + me.setUid(visitor.getUid()); + me.setName(visitor.getName()); + me.setAuthHash(getAuthToken(visitor)); + List<Integer> 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 ResponseEntity<Void> updateMe(@Visitor 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": + crosspostService.deleteTwitterToken(visitor.getUid()); + break; + case "vk": + crosspostService.deleteVKUser(visitor.getUid()); + break; + case "durov": + telegramService.deleteTelegramUser(visitor.getUid()); + break; + } + } + return ResponseEntity.ok().build(); + } + @PostMapping("/api/me/subscribe") + public ResponseEntity<Void> subscribeMe(@Visitor User visitor, String email) { + // TODO: check status + emailService.setNotificationsEmail(visitor.getUid(), email); + return ResponseEntity.ok().build(); + } + @PostMapping("/api/me/upload") + public void updateInfo(@Visitor User visitor, + @RequestParam MultipartFile avatar) throws IOException { + String avatarTmpPath = HttpUtils.receiveMultiPartFile(avatar, tmpDir).getHost(); + if (StringUtils.isNotEmpty(avatarTmpPath)) { + imagesService.saveAvatar(avatarTmpPath, visitor.getUid()); + } + } + + @RequestMapping(value = "/api/users/read", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public List<User> doGetUserRead( + @Visitor 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<User> 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<User> doGetUserReaders( + @Visitor 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<User> readers = userService.getUserReaders(uid); + readers.forEach(r -> r.setAvatar(webApp.getAvatarUrl(r))); + return readers; + } + throw new HttpNotFoundException(); + } + + @GetMapping("/api/info/{uname}") + public User getUserInfo(@Visitor 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<String> getJIDs() { + return userService.getAllJIDs(this); + } + public List<String> getEmails() { + return userService.getEmails(this); + } + public String getActiveEmail() { + return emailService.getNotificationsEmail(this.getUid()); + } + public String getTwitterName() { + return crosspostService.getTwitterName(this.getUid()); + } + public String getTelegramName() { + return crosspostService.getTelegramName(this.getUid()); + } + public ApplicationStatus getFacebookStatus() { + return crosspostService.getFbCrossPostStatus(this.getUid()); + } + } +} |