diff options
5 files changed, 63 insertions, 34 deletions
diff --git a/juick-common/src/main/java/com/juick/service/UserService.java b/juick-common/src/main/java/com/juick/service/UserService.java index cfeaaa51..f999037c 100644 --- a/juick-common/src/main/java/com/juick/service/UserService.java +++ b/juick-common/src/main/java/com/juick/service/UserService.java @@ -46,7 +46,7 @@ public interface UserService { @Nonnull User getUserByName(String username); - User getUserByEmail(String email); + @Nonnull User getUserByEmail(String email); User getUserByJID(String jid); diff --git a/juick-server/src/main/java/com/juick/server/EmailManager.java b/juick-server/src/main/java/com/juick/server/EmailManager.java index 66e84358..6e8d0d76 100644 --- a/juick-server/src/main/java/com/juick/server/EmailManager.java +++ b/juick-server/src/main/java/com/juick/server/EmailManager.java @@ -8,6 +8,7 @@ import com.juick.service.MessagesService; import com.juick.service.SubscriptionService; import com.juick.service.UserService; import com.juick.util.MessageUtils; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationListener; @@ -23,7 +24,9 @@ import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Properties; import static com.juick.formatters.PlainTextFormatter.formatPost; @@ -68,6 +71,31 @@ public class EmailManager implements ApplicationListener<MessageEvent> { } private void emailNotify(String email, String subject, Message msg) { + Map<String, String> headers = new HashMap<>(); + if (!MessageUtils.isPM(msg)) { + headers.put("Message-ID", String.format("<%d.%d@juick.com>", msg.getMid(), msg.getRid())); + } + if (MessageUtils.isReply(msg)) { + if (msg.getReplyto() > 0) { + Message replyto = messagesService.getReply(msg.getMid(), msg.getReplyto()); + headers.put("In-Reply-To", String.format("<%d.%d@juick.com>", replyto.getMid(), replyto.getRid())); + } else { + Message original = messagesService.getMessage(msg.getMid()); + headers.put("In-Reply-To", String.format("<%d.%d@juick.com>", original.getMid(), original.getRid())); + } + } + String plainText = String.format("%s\n\n--\nYou are receiving this because you are subscribed to this user " + + ", discussion or tag. Reply to this email directly or view it on Juick: %s.", + formatPost(msg), formatUrl(msg)); + String hash = userService.getHashByUID(userService.getUserByEmail(email).getUid()); + String htmlText = String.format("%s<br /><br />--<br />You are receiving this because you are subscribed to this user" + + ", discussion or tag. Reply to this email directly or <a href=\"%s\"><img src=\"https://api.juick.com/thread/mark_read/%d-%d.gif?hash=%s\" />view it</a> on Juick." + + "<br /><a href=\"https://juick.com/settings?hash=%s\">Configure or disable notifications</a>", + MessageUtils.formatHtml(msg), formatUrl(msg), + msg.getMid(), msg.getRid(), hash, hash); + sendEmail(email, subject, plainText, htmlText, headers); + } + public void sendEmail(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); @@ -75,42 +103,30 @@ public class EmailManager implements ApplicationListener<MessageEvent> { Transport transport = session.getTransport("smtp"); MimeMessage message = new MimeMessage(session) { protected void updateMessageID() throws MessagingException { - if (!MessageUtils.isPM(msg)) { - setHeader("Message-ID", String.format("<%d.%d@juick.com>", msg.getMid(), msg.getRid())); - } - if (MessageUtils.isReply(msg)) { - if (msg.getReplyto() > 0) { - Message replyto = messagesService.getReply(msg.getMid(), msg.getReplyto()); - setHeader("In-Reply-To", String.format("<%d.%d@juick.com>", replyto.getMid(), replyto.getRid())); - } else { - Message original = messagesService.getMessage(msg.getMid()); - setHeader("In-Reply-To", String.format("<%d.%d@juick.com>", original.getMid(), original.getRid())); - } + for (Map.Entry<String, String> entry: messageHeaders.entrySet()) { + setHeader(entry.getKey(), entry.getValue()); } } }; message.setFrom(new InternetAddress("juick@juick.com")); - message.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(email)); + message.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(to)); message.setSubject(subject); - String plainText = String.format("%s\n\n--\nYou are receiving this because you are subscribed to this user " + - ", discussion or tag. Reply to this email directly or view it on Juick: %s.", - formatPost(msg), formatUrl(msg)); MimeBodyPart textBodyPart = new MimeBodyPart(); - String hash = userService.getHashByUID(userService.getUserByEmail(email).getUid()); - textBodyPart.setContent(plainText, "text/plain; charset=UTF-8"); - String htmlText = String.format("%s<br /><br />--<br />You are receiving this because you are subscribed to this user" + - ", discussion or tag. Reply to this email directly or <a href=\"%s\"><img src=\"https://api.juick.com/thread/mark_read/%d-%d.gif?hash=%s\" />view it</a> on Juick." + - "<br /><a href=\"https://juick.com/settings?hash=%s\">Configure or disable notifications</a>", - MessageUtils.formatHtml(msg), formatUrl(msg), - msg.getMid(), msg.getRid(), hash, hash); - MimeBodyPart htmlBodyPart = new MimeBodyPart(); - htmlBodyPart.setContent(htmlText, "text/html; charset=UTF-8"); + textBodyPart.setContent(textPart, "text/plain; charset=UTF-8"); + Multipart multipart = new MimeMultipart("alternative"); multipart.addBodyPart(textBodyPart); - multipart.addBodyPart(htmlBodyPart); + if (StringUtils.isNotBlank(htmlPart)) { + MimeBodyPart htmlBodyPart = new MimeBodyPart(); + htmlBodyPart.setContent(htmlPart, "text/html; charset=UTF-8"); + multipart.addBodyPart(htmlBodyPart); + } message.setContent(multipart); - message.setHeader("List-Unsubscribe", String.format("https://juick.com/settings?hash=%s", - userService.getHashByUID(userService.getUserByEmail(email).getUid()))); + User emailUser = userService.getUserByEmail(to); + if (!emailUser.isAnonymous()) { + message.setHeader("List-Unsubscribe", String.format("https://juick.com/settings?hash=%s", + userService.getHashByUID(emailUser.getUid()))); + } message.saveChanges(); transport.connect(); transport.sendMessage(message, message.getAllRecipients()); diff --git a/juick-server/src/main/java/com/juick/server/api/Service.java b/juick-server/src/main/java/com/juick/server/api/Service.java index f67f6986..527fb739 100644 --- a/juick-server/src/main/java/com/juick/server/api/Service.java +++ b/juick-server/src/main/java/com/juick/server/api/Service.java @@ -5,9 +5,11 @@ import com.juick.server.CommandsManager; import com.juick.server.EmailManager; import com.juick.server.util.HttpForbiddenException; import com.juick.server.util.UserUtils; +import com.juick.service.EmailService; import com.juick.service.UserService; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.mail.util.MimeMessageParser; import org.slf4j.Logger; @@ -29,22 +31,26 @@ import java.io.InputStream; import java.net.URI; import java.nio.charset.StandardCharsets; import java.nio.file.Paths; -import java.util.Properties; -import java.util.Scanner; -import java.util.UUID; +import java.util.*; @Controller public class Service { private static Logger logger = LoggerFactory.getLogger(Post.class); @Inject private UserService userService; - @Inject - CommandsManager commandsManager; + private EmailService emailService; + @Inject + private CommandsManager commandsManager; + @Inject + private EmailManager emailManager; @Value("${api_user:juick}") private String serviceUser; @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}") private String tmpDir; + @Value("${banned_emails:}") + private String[] ignoredEmails; + Session session = Session.getDefaultInstance(new Properties()); @ApiIgnore @@ -108,7 +114,12 @@ public class Service { : URI.create(StringUtils.EMPTY); commandsManager.processCommand(visitor, body[0], attachmentUri); } else { - logger.info("not registered: {}", from); + if (!Arrays.asList(ignoredEmails).contains(from)) { + 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&code=%s", verificationCode); + emailManager.sendEmail(from, "Juick registration", signupUrl, StringUtils.EMPTY, Collections.emptyMap()); + } } } else { throw new HttpForbiddenException(); diff --git a/juick-server/src/main/java/com/juick/service/UserServiceImpl.java b/juick-server/src/main/java/com/juick/service/UserServiceImpl.java index bcdb7a13..e841b539 100644 --- a/juick-server/src/main/java/com/juick/service/UserServiceImpl.java +++ b/juick-server/src/main/java/com/juick/service/UserServiceImpl.java @@ -142,6 +142,7 @@ public class UserServiceImpl extends BaseJdbcService implements UserService { @Override @Transactional(readOnly = true) + @Nonnull public User getUserByEmail(String email) { if (StringUtils.isNotBlank(email)) { List<User> list = getJdbcTemplate().query( diff --git a/juick-server/src/main/resources/db/migration/V1.3__Nullable user_id column in auth table.sql b/juick-server/src/main/resources/db/migration/V1.3__Nullable user_id column in auth table.sql new file mode 100644 index 00000000..ced85ade --- /dev/null +++ b/juick-server/src/main/resources/db/migration/V1.3__Nullable user_id column in auth table.sql @@ -0,0 +1 @@ +ALTER TABLE auth MODIFY COLUMN user_id int(10) unsigned NULL;
\ No newline at end of file |