aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2019-08-21 11:09:54 +0300
committerGravatar Vitaly Takmazov2019-08-21 11:09:54 +0300
commitb10719e4c69b489830001c9707f6e2eba265abad (patch)
tree29c14701fb43a3380cb71a07f48efa86eccfe0e9
parentd9d481d824f920f797cff4d9ca92c8cd9b895389 (diff)
Settings API
-rw-r--r--src/main/java/com/juick/server/EmailManager.java9
-rw-r--r--src/main/java/com/juick/server/api/Service.java2
-rw-r--r--src/main/java/com/juick/server/api/Users.java77
-rw-r--r--src/test/java/com/juick/server/tests/ServerTests.java37
4 files changed, 119 insertions, 6 deletions
diff --git a/src/main/java/com/juick/server/EmailManager.java b/src/main/java/com/juick/server/EmailManager.java
index 3d17a041..bd77d8d6 100644
--- a/src/main/java/com/juick/server/EmailManager.java
+++ b/src/main/java/com/juick/server/EmailManager.java
@@ -119,9 +119,9 @@ public class EmailManager implements NotificationListener {
String plainText = renderPlaintext(formatPost(msg), formatUrl(msg)).orElseThrow(IllegalStateException::new);
String hash = userService.getHashByUID(userService.getUserByEmail(email).getUid());
String htmlText = renderHtml(MessageUtils.formatHtml(msg), formatUrl(msg), msg, hash).orElseThrow(IllegalStateException::new);
- sendEmail(email, subject, plainText, htmlText, headers);
+ sendEmail(StringUtils.EMPTY, email, subject, plainText, htmlText, headers);
}
- public void sendEmail(String to, String subject, String textPart, String htmlPart, Map<String, String> messageHeaders) {
+ public boolean sendEmail(String from, String to, String subject, String textPart, String htmlPart, Map<String, String> messageHeaders) {
Properties prop = System.getProperties();
prop.put("mail.smtp.starttls.enable", "true");
Session session = Session.getDefaultInstance(prop);
@@ -134,7 +134,8 @@ public class EmailManager implements NotificationListener {
}
}
};
- message.setFrom(new InternetAddress("juick@juick.com"));
+ String fromAddress = StringUtils.isNotEmpty(from) ? from : "juick@juick.com";
+ message.setFrom(fromAddress);
message.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(to));
message.setSubject(subject);
MimeBodyPart textBodyPart = new MimeBodyPart();
@@ -161,8 +162,10 @@ public class EmailManager implements NotificationListener {
message.saveChanges();
transport.connect();
transport.sendMessage(message, message.getAllRecipients());
+ return true;
} catch (MessagingException ex) {
logger.error("mail exception", ex);
+ return false;
}
}
diff --git a/src/main/java/com/juick/server/api/Service.java b/src/main/java/com/juick/server/api/Service.java
index 2a86c5e7..f137f2f7 100644
--- a/src/main/java/com/juick/server/api/Service.java
+++ b/src/main/java/com/juick/server/api/Service.java
@@ -152,7 +152,7 @@ public class Service {
String verificationCode = RandomStringUtils.randomAlphanumeric(8).toUpperCase();
emailService.addVerificationCode(null, from, verificationCode);
String signupUrl = String.format("Follow this link to create Juick account: https://juick.com/signup?type=email&hash=%s", verificationCode);
- emailManager.sendEmail(from, "Juick registration", signupUrl, StringUtils.EMPTY, Collections.emptyMap());
+ emailManager.sendEmail("noreply@juick.com", from, "Juick registration", signupUrl, StringUtils.EMPTY, Collections.emptyMap());
}
}
} else {
diff --git a/src/main/java/com/juick/server/api/Users.java b/src/main/java/com/juick/server/api/Users.java
index 0db710c9..74a720d4 100644
--- a/src/main/java/com/juick/server/api/Users.java
+++ b/src/main/java/com/juick/server/api/Users.java
@@ -20,6 +20,8 @@ package com.juick.server.api;
import com.juick.User;
import com.juick.model.AnonymousUser;
import com.juick.model.ApplicationStatus;
+import com.juick.server.EmailManager;
+import com.juick.server.util.HttpBadRequestException;
import com.juick.server.util.HttpNotFoundException;
import com.juick.server.util.HttpUtils;
import com.juick.server.util.WebUtils;
@@ -28,19 +30,31 @@ import com.juick.service.*;
import com.juick.service.security.annotation.Visitor;
import com.juick.service.security.entities.JuickUser;
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.http.HttpStatus;
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 javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import static org.springframework.http.ResponseEntity.ok;
+import static org.springframework.http.ResponseEntity.status;
+
/**
* @author ugnich
*/
@@ -53,6 +67,8 @@ public class Users {
@Inject
private CrosspostService crosspostService;
@Inject
+ private TelegramService telegramService;
+ @Inject
private EmailService emailService;
@Inject
private TagService tagService;
@@ -62,6 +78,8 @@ public class Users {
private ImagesService imagesService;
@Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
private String tmpDir;
+ @Inject
+ private EmailManager emailManager;
@RequestMapping(value = "/api/auth", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String getAuthToken(@Visitor User visitor) {
@@ -106,6 +124,63 @@ public class Users {
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)) {
+ if (!emailManager.sendEmail("noreply@juick.com", newEmail, "Juick authorization link",
+ String.format("Follow link to attach this email to Juick account:\n" +
+ "http://juick.com/settings?page=auth-email&code=%s\n\n" +
+ "If you don't know, what this mean - just ignore this mail.\n", authCode),
+ StringUtils.EMPTY, Collections.emptyMap())) {
+ throw new HttpBadRequestException();
+ };
+ }
+ }
+ }
+ 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 {
@@ -190,7 +265,7 @@ public class Users {
}
return IOUtils.toByteArray(URI.create(webApp.getAvatarUrl(user)));
}
- class SecureUser extends User {
+ public class SecureUser extends User {
public String getHash() {
return getAuthHash();
}
diff --git a/src/test/java/com/juick/server/tests/ServerTests.java b/src/test/java/com/juick/server/tests/ServerTests.java
index 688e6148..e113c44a 100644
--- a/src/test/java/com/juick/server/tests/ServerTests.java
+++ b/src/test/java/com/juick/server/tests/ServerTests.java
@@ -34,6 +34,7 @@ import com.juick.model.CommandResult;
import com.juick.model.PrivateChats;
import com.juick.model.TagStats;
import com.juick.server.*;
+import com.juick.server.api.Users;
import com.juick.server.api.activity.Profile;
import com.juick.server.api.activity.model.Context;
import com.juick.server.api.activity.model.activities.*;
@@ -254,6 +255,9 @@ public class ServerTests {
@Inject
private ApplicationEventPublisher applicationEventPublisher;
+ @Inject
+ private Users usersController;
+
private static User ugnich, freefd, juick;
static String ugnichName, ugnichPassword, freefdName, freefdPassword, juickName, juickPassword;
URI emptyUri = URI.create(StringUtils.EMPTY);
@@ -1936,7 +1940,7 @@ public class ServerTests {
assertThat(userService.getUserByName("ugnich").isVerified(), is(true));
}
@Test
- public void avatarUploadOverApi() throws Exception {
+ public void changeProfileOverApi() throws Exception {
ClassPathResource defaultAvatar = new ClassPathResource("static/av-96.png");
String hash = DigestUtils.md5DigestAsHex(IOUtils.toByteArray(defaultAvatar.getInputStream()));
assertThat(webApp.getAvatarUrl(userService.getUserByName(freefdName)), is(String.format("http://localhost:8080/av-96-%s.png", hash)));
@@ -1950,7 +1954,38 @@ public class ServerTests {
String newHash = DigestUtils.md5DigestAsHex(newAvatarData);
URI newUri = Paths.get(imgDir, "ao", String.format("%d.png", freefd.getUid())).toUri();
assertThat(DigestUtils.md5DigestAsHex(IOUtils.toByteArray(newUri)), is(newHash));
+ mockMvc.perform(post("/api/me")
+ .with(httpBasic(ugnichName, ugnichPassword))
+ .param("password", "newPassword"))
+ .andExpect(status().isOk());
+ mockMvc.perform(get("/api/me")
+ .with(httpBasic(ugnichName, ugnichPassword)))
+ .andExpect(status().isUnauthorized());
+ mockMvc.perform(post("/api/me")
+ .with(httpBasic(ugnichName, "newPassword"))
+ .param("password", ugnichPassword))
+ .andExpect(status().isOk());
+ mockMvc.perform(get("/api/me")
+ .with(httpBasic(ugnichName, ugnichPassword)))
+ .andExpect(status().isOk());
+ assertThat(usersController.getMe(ugnich).getJIDs().size(), is(0));
+ jdbcTemplate.update("INSERT INTO jids(user_id, jid) VALUES(?, ?)",
+ ugnich.getUid(), "test@example.com");
+ jdbcTemplate.update("INSERT INTO jids(user_id, jid) VALUES(?, ?)",
+ ugnich.getUid(), "test2@example.com");
+ assertThat(usersController.getMe(ugnich).getJIDs().size(), is(2));
+ mockMvc.perform(post("/api/me")
+ .with(httpBasic(ugnichName, ugnichPassword))
+ .param("jid-del", "test@example.com"))
+ .andExpect(status().isOk());
+ assertThat(usersController.getMe(ugnich).getJIDs().size(), is(1));
+ mockMvc.perform(post("/api/me")
+ .with(httpBasic(ugnichName, ugnichPassword))
+ .param("jid-del", "test2@example.com"))
+ .andExpect(status().isBadRequest());
+ jdbcTemplate.execute("DELETE FROM jids");
}
+
@Test
public void varyMvcResponse() throws Exception {
mockMvc.perform(get("/"))