package com.juick.www.controllers; import com.juick.User; import com.juick.server.helpers.NotifyOpts; import com.juick.server.helpers.UserInfo; import com.juick.server.util.HttpBadRequestException; import com.juick.server.util.HttpForbiddenException; import com.juick.server.util.HttpUtils; import com.juick.service.*; import com.juick.util.UserUtils; import net.coobird.thumbnailator.Thumbnails; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.env.Environment; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; 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 javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; /** * Created by aalexeev on 11/21/16. */ @Controller public class SettingsController { private static final Logger logger = LoggerFactory.getLogger(SettingsController.class); @Inject UserService userService; @Inject TagService tagService; @Inject CrosspostService crosspostService; @Inject SubscriptionService subscriptionService; @Inject EmailService emailService; @Inject TelegramService telegramService; @Inject Environment env; @RequestMapping(value = "settings", method = RequestMethod.GET) public String showSettings( @RequestParam(required = false) String page, @RequestParam(required = false) String code, ModelMap context) { User visitor = UserUtils.getCurrentUser(); if (visitor.getUid() == 0) { return "redirect:/login"; } List pages = Arrays.asList("main", "password", "about", "auth-email", "privacy"); if (StringUtils.isEmpty(page) || !pages.contains(page)) { page = "main"; } context.put("title", "Настройки"); context.put("visitor", visitor); context.put("tags", tagService.getPopularTags()); context.put("auths", userService.getAuthCodes(visitor)); context.put("eopts", userService.getEmailOpts(visitor)); context.put("ehash", userService.getEmailHash(visitor)); context.put("emails", userService.getEmails(visitor)); context.put("jids", userService.getAllJIDs(visitor)); List hours = IntStream.rangeClosed(0, 23).boxed() .map(i -> StringUtils.leftPad(String.format("%d", i), 2, "0")).collect(Collectors.toList()); context.put("hours", hours); context.put("fbstatus", crosspostService.getFbCrossPostStatus(visitor.getUid())); context.put("twitter_name", crosspostService.getTwitterName(visitor.getUid())); context.put("telegram_name", crosspostService.getTelegramName(visitor.getUid())); context.put("notify_options", subscriptionService.getNotifyOptions(visitor)); context.put("userinfo", userService.getUserInfo(visitor)); if (page.equals("auth-email")) { String response = emailService.verifyAddressByCode(visitor.getUid(), code) ? "OK!" : "Sorry, code unknown."; context.put("result", response); } return String.format("views/settings_%s", page); } @RequestMapping(value = "/settings", method = RequestMethod.POST) protected String doPost( HttpServletResponse response, @RequestParam String page, @RequestParam(required = false) String password, @RequestParam(required = false) String jnotify, @RequestParam(required = false) String subscr_notify, @RequestParam(required = false) String recomm, @RequestParam(required = false) String fullname, @RequestParam(required = false) String country, @RequestParam(required = false) String url, @RequestParam(required = false) String descr, @RequestParam(required = false) MultipartFile avatar, @RequestParam(required = false) String account, @RequestParam(required = false) String time, ModelMap context) throws IOException { User visitor = UserUtils.getCurrentUser(); if (visitor.getUid() == 0) { throw new HttpForbiddenException(); } List pages = Arrays.asList("main", "password", "about", "email", "email-add", "email-del", "email-subscr", "auth-email", "privacy", "jid-del", "twitter-del", "telegram-del", "facebook-disable", "facebook-enable", "vk-del"); if (StringUtils.isEmpty(page) || !pages.contains(page)) { throw new HttpBadRequestException(); } String result = ""; switch (page) { case "password": if (userService.updatePassword(visitor, password)) { result = "

Password has been changed.

"; String hash = userService.getHashByUID(visitor.getUid()); Cookie c = new Cookie("hash", hash); c.setMaxAge(365 * 24 * 60 * 60); // FIXME: use spring-security response.addCookie(c); } break; case "main": NotifyOpts opts = new NotifyOpts(); opts.setRepliesEnabled(StringUtils.isNotEmpty(jnotify)); opts.setSubscriptionsEnabled(StringUtils.isNotEmpty(subscr_notify)); opts.setRecommendationsEnabled(StringUtils.isNotEmpty(recomm)); if (subscriptionService.setNotifyOptions(visitor, opts)) { result = "

Notification options has been updated

"; } break; case "about": UserInfo info = new UserInfo(); info.setFullName(fullname); info.setCountry(country); info.setUrl(url); info.setDescription(descr); String imgPath = env.getProperty("img_path", "/var/www/juick.com/i/"); String tmpDir = env.getProperty("upload_tmp_dir", "/var/www/juick.com/i/tmp/"); String avatarTmpPath = HttpUtils.receiveMultiPartFile(avatar, tmpDir); if (StringUtils.isNotEmpty(avatarTmpPath)) { String originalExtension = FilenameUtils.getExtension(avatarTmpPath); String originalName = String.format("%s.%s", visitor.getUid(), originalExtension); String targetName = String.format("%s.png", visitor.getUid()); Path ao = Paths.get(imgPath, "ao", originalName); Path a = Paths.get(imgPath, "a", targetName); Path as = Paths.get(imgPath, "as", targetName); Files.move(Paths.get(tmpDir, avatarTmpPath), ao, StandardCopyOption.REPLACE_EXISTING); Thumbnails.of(ao.toFile()).size(96, 96).toFile(a.toFile()); Thumbnails.of(ao.toFile()).size(32, 32).toFile(as.toFile()); } if (userService.updateUserInfo(visitor, info)) { result = String.format("

Your info is updated.

Back to blog.

", visitor.getName()); } break; case "jid-del": // FIXME: stop using ugnich-csv in parameters // String[] params = request.getParameter("delete").split(";", 2); // int res = -1; // if (params[0].equals("xmpp")) { // res = sql.update("DELETE FROM jids WHERE user_id=? AND jid=?", visitor.getUid(), params[1]); // } else if (params[0].equals("xmpp-unauth")) { // res = sql.update("DELETE FROM auth WHERE user_id=? AND protocol='xmpp' AND account=?", visitor.getUid(), params[1]); // } // if (res == 1) { // result = "

Deleted. Back.

"; // } else { // result = "

Error

"; // } break; case "email": String newHash = userService.updateSecretEmail(visitor); if (StringUtils.isNotEmpty(newHash)) { result = String.format("

New secret email: %s@mail.juick.com

" + "

Back.

", newHash); } else { throw new HttpBadRequestException(); } break; case "email-add": try { emailService.verifyAddressByCode(visitor.getUid(), account); } catch (EmptyResultDataAccessException e) { String authCode = UserUtils.generateHash(8); if (emailService.addVerificationCode(visitor.getUid(), account, authCode)) { Session session = Session.getDefaultInstance(System.getProperties()); try { MimeMessage message = new MimeMessage(session); message.setFrom(new InternetAddress("noreply@mail.juick.com")); message.addRecipient(Message.RecipientType.TO, new InternetAddress(account)); message.setSubject("Juick authorization link"); message.setText(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)); Transport.send(message); result = "

Authorization link has been sent to your email. Follow it to proceed.

" + "

Back

"; } catch (MessagingException ex) { logger.error("mail exception", ex); throw new HttpBadRequestException(); } } } break; case "email-del": if (emailService.deleteEmail(visitor.getUid(), account)) { result = "

Deleted. Back.

"; } else { result = "

An error occured while deleting.

"; } break; case "email-subscr": if (emailService.setSubscriptionHour(visitor.getUid(), account, time)) { result = String.format("

Saved! Will send to %s at %s:00 GMT." + "

Back

", account, time); } else { result = "

Disabled.

Back

"; } break; case "twitter-del": crosspostService.deleteTwitterToken(visitor.getUid()); // FIXME: use spring-security // for (Cookie cookie : request.getCookies()) { // if (cookie.getName().equals("request_token")) { // cookie.setMaxAge(0); // response.addCookie(cookie); // } // if (cookie.getName().equals("request_token_secret")) { // cookie.setMaxAge(0); // response.addCookie(cookie); // } // } result = "

Back

"; break; case "telegram-del": telegramService.deleteTelegramUser(visitor.getUid()); result = "

Back

"; break; case "facebook-disable": crosspostService.disableFBCrosspost(visitor.getUid()); result = "

Back

"; break; case "facebook-enable": crosspostService.enableFBCrosspost(visitor.getUid()); result = "

Back

"; break; case "vk-del": crosspostService.deleteVKUser(visitor.getUid()); result = "

Back

"; break; default: throw new HttpBadRequestException(); } context.put("title", "Настройки"); context.put("visitor", visitor); context.put("result", result); return "views/settings_result"; } }