aboutsummaryrefslogblamecommitdiff
path: root/src/main/java/com/juick/www/controllers/Settings.java
blob: 5cda7bc4b4718cb6902c214fe257f331f6987fb7 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  
                                 












                                                                           
                                  
 
                            
                                  
                                              
                            
                           
                                                     



                                                          

















                                                            
                      
                                









                                                                                 














                                                                      
                          
                            
                                  
                          
                                                                              

                                            
                                                            




                                                                                                 
                                                                                                             















                                                                                                            







                                                                     



                                                                     
                                





























                                                                                                                      


                                                                      


                                                                                                
                                                          























                                                                                                                                     
                                                                                      




































































                                                                                                                                 
                                         


                                                                        









                                                                                     
 
/*
 * 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 <http://www.gnu.org/licenses/>.
 */
package com.juick.www.controllers;

import com.juick.model.User;
import com.juick.model.NotifyOpts;
import com.juick.util.HttpBadRequestException;
import com.juick.util.HttpUtils;
import com.juick.www.WebApp;
import com.juick.service.*;
import com.juick.service.security.annotation.Visitor;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 *
 * @author Ugnich Anton
 */
@Controller
public class Settings {
    private static final Logger logger = LoggerFactory.getLogger(Settings.class);

    @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
    private String tmpDir;
    @Inject
    private TagService tagService;
    @Inject
    private UserService userService;
    @Inject
    private CrosspostService crosspostService;
    @Inject
    private SubscriptionService subscriptionService;
    @Inject
    private EmailService emailService;
    @Inject
    private TelegramService telegramService;
    @Inject
    private ImagesService imagesService;
    @Inject
    private WebApp webApp;

    @GetMapping("/settings")
    protected String doGet(
            @Visitor User visitor,
            Locale locale,
            HttpServletRequest request,
            HttpServletResponse response, ModelMap model) throws IOException {
        if (visitor.isAnonymous()) {
            response.sendRedirect("/login");
        }
        visitor.setAvatar(webApp.getAvatarWebPath(visitor));
        List<String> pages = Arrays.asList("main", "password", "about", "auth-email", "privacy");
        String page = request.getParameter("page");
        if (StringUtils.isEmpty(page) || !pages.contains(page)) {
            page = "main";
        }

        model.addAttribute("title", ResourceBundle.getBundle("messages", locale).getString("link.settings"));
        model.addAttribute("visitor", visitor);
        model.addAttribute("tags", tagService.getPopularTags());
        model.addAttribute("auths", userService.getAuthCodes(visitor));
        model.addAttribute("email_active", emailService.getNotificationsEmail(visitor.getUid()));
        model.addAttribute("ehash", userService.getEmailHash(visitor));
        model.addAttribute("emails", userService.getEmails(visitor));
        model.addAttribute("jids", userService.getAllJIDs(visitor));
        List<String> hours = IntStream.rangeClosed(0, 23).boxed()
                .map(i -> StringUtils.leftPad(String.format("%d", i), 2, "0")).collect(Collectors.toList());
        model.addAttribute("hours", hours);
        model.addAttribute("fbstatus", crosspostService.getFbCrossPostStatus(visitor.getUid()));
        model.addAttribute("twitter_name", crosspostService.getTwitterName(visitor.getUid()));
        model.addAttribute("telegram_name", crosspostService.getTelegramName(visitor.getUid()));
        model.addAttribute("notify_options", subscriptionService.getNotifyOptions(visitor));
        model.addAttribute("userinfo", userService.getUserInfo(visitor));
        if (page.equals("auth-email")) {
            if (emailService.verifyAddressByCode(visitor.getUid(), request.getParameter("code"))) {
                model.addAttribute("result", "OK!");
            } else {
                model.addAttribute("result", "Sorry, code unknown.");
            }
        }
        return String.format("views/settings_%s", page);
    }

    @PostMapping("/settings")
    protected String doPost(
            @Visitor User visitor,
            HttpServletRequest request, HttpServletResponse response,
            @RequestParam(required = false) MultipartFile avatar,
            ModelMap model)
            throws IOException {
        if (visitor.isAnonymous()) {
            throw new HttpBadRequestException();
        }
        List<String> 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");
        String page = request.getParameter("page");
        if (StringUtils.isEmpty(page) || !pages.contains(page)) {
            throw new HttpBadRequestException();
        }
        String result = StringUtils.EMPTY;
        switch (page) {
            case "password":
                if (userService.updatePassword(visitor, request.getParameter("password"))) {
                    result = "<p>Password has been changed.</p>";
                    String hash = userService.getHashByUID(visitor.getUid());
                    Cookie c = new Cookie("hash", hash);
                    c.setMaxAge(365 * 24 * 60 * 60);
                    response.addCookie(c);
                }
                break;
            case "main":
                NotifyOpts opts = new NotifyOpts();
                opts.setRepliesEnabled(StringUtils.isNotEmpty(request.getParameter("jnotify")));
                opts.setSubscriptionsEnabled(StringUtils.isNotEmpty(request.getParameter("subscr_notify")));
                opts.setRecommendationsEnabled(StringUtils.isNotEmpty(request.getParameter("recomm")));
                if (subscriptionService.setNotifyOptions(visitor, opts)) {
                    result = "<p>Notification options has been updated</p>";
                }
                break;
            case "about":
                visitor.setFullName(request.getParameter("fullname"));
                visitor.setCountry(request.getParameter("country"));
                visitor.setUrl(request.getParameter("url"));
                visitor.setDescription(request.getParameter("descr"));
                String avatarTmpPath = HttpUtils.receiveMultiPartFile(avatar, tmpDir).getHost();
                if (StringUtils.isNotEmpty(avatarTmpPath)) {
                    imagesService.saveAvatar(avatarTmpPath, visitor.getUid());
                }
                if (userService.updateUserInfo(visitor)) {
                    result = String.format("<p>Your info is updated.</p><p><a href='/%s/'>Back to blog</a>.</p>", visitor.getName());
                }
                break;
            case "jid-del":
                // FIXME: stop using ugnich-csv in parameters
                String[] params = request.getParameter("delete").split(";", 2);
                boolean res = false;
                if (params[0].equals("xmpp")) {
                    res = userService.deleteJID(visitor.getUid(), params[1]);
                } else if (params[0].equals("xmpp-unauth")) {
                    res = userService.unauthJID(visitor.getUid(), params[1]);
                }
                if (res) {
                    result = "<p>Deleted. <a href=\"/settings\">Back</a>.</p>";
                } else {
                    result = "<p>Error</p>";
                }
                break;
            case "email-add":
                if (!emailService.verifyAddressByCode(visitor.getUid(), request.getParameter("account"))) {
                    String authCode = RandomStringUtils.randomAlphanumeric(8).toUpperCase();
                    if (emailService.addVerificationCode(visitor.getUid(), request.getParameter("account"), authCode)) {
                        Session session = Session.getDefaultInstance(System.getProperties());
                        try {
                            MimeMessage message = new MimeMessage(session);
                            message.setFrom(new InternetAddress("noreply@juick.com"));
                            message.addRecipient(Message.RecipientType.TO, new InternetAddress(request.getParameter("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 = "<p>Authorization link has been sent to your email. Follow it to proceed.</p>" +
                                    "<p><a href=\"/settings\">Back</a></p>";

                        } catch (MessagingException ex) {
                            logger.error("mail exception", ex);
                            throw new HttpBadRequestException();
                        }
                    }
                }
                break;
            case "email-del":
                if (emailService.deleteEmail(visitor.getUid(), request.getParameter("account"))) {
                    result = "<p>Deleted. <a href=\"/settings\">Back</a>.</p>";
                } else {
                    result = "<p>An error occured while deleting.</p>";
                }
                break;
            case "email-subscr":
                if (emailService.setNotificationsEmail(visitor.getUid(), request.getParameter("account"))) {
                    result = String.format("<p>Saved! Will send notifications to <strong>%s</strong>." +
                            "</p><p><a href=\"/settings\">Back</a></p>", request.getParameter("account"));
                } else {
                    result = "<p>Disabled.</p><p><a href=\"/settings\">Back</a></p>";
                }
                break;
            case "twitter-del":
                crosspostService.deleteTwitterToken(visitor.getUid());
                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 = "<p><a href=\"/settings\">Back</a></p>";
                break;
            case "telegram-del":
                telegramService.deleteTelegramUser(visitor.getUid());
                result = "<p><a href=\"/settings\">Back</a></p>";
                break;
            case "facebook-disable":
                crosspostService.disableFBCrosspost(visitor.getUid());
                result = "<p><a href=\"/settings\">Back</a></p>";
                break;
            case "facebook-enable":
                crosspostService.enableFBCrosspost(visitor.getUid());
                result = "<p><a href=\"/settings\">Back</a></p>";
                break;
            case "vk-del":
                crosspostService.deleteVKUser(visitor.getUid());
                result = "<p><a href=\"/settings\">Back</a></p>";
                break;
            default:
                throw new HttpBadRequestException();
        }

        model.addAttribute("title", "Настройки");
        model.addAttribute("visitor", visitor);
        model.addAttribute("result", result);
        return "views/settings_result";
    }
    @PostMapping("/settings/unsubscribe")
    public String unsubscribeOneClick(
            @Visitor User user,
            @RequestParam(name = "List-Unsubscribe") String unsubscribe,
            ModelMap model) {
        if (!user.isAnonymous()) {
            if (unsubscribe.equals("One-Click")) {
                emailService.setNotificationsEmail(user.getUid(), StringUtils.EMPTY);
                model.addAttribute("title", "Настройки");
                model.addAttribute("visitor", user);
                model.addAttribute("result", "Unsubscribed");
                return "views/settings_result";
            }
        }
        throw new HttpBadRequestException();
    }
}