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












                                                                           
                                  
 



                                

                                  
 

                                        


                                                    
                                              
                            
 
                                               








                                                


                                                  
                                                             





                                                            






                                                                                 



                                    


                                            
                                          
                          
                                                                
                            
                           
                                                   
                          
                                                                               
                                                                          
                                                            
                                                                                                 
                                    
                          
                                                                                                             


                                                                                                 

                                                                     
                                                                                        
                                           

                                                                                           
                                                                         
                                                                           







                                                                     
                            
                                                   
                                                                     
                                                                    
                           
                                



















                                                                                                                      
                         


                                                                      
                                                                                                                                   
                                                            
                                                                      
                 
                                                          
                                                                                                                                     
                                                                                           





















                                                                                                                        
                                                                                      






























                                                                                                                                 
                                                                 











                                                                          

                                                                         

                                                                 
                                                                 

                                                                 
                                                                

                                                                 
                                                           









                                                                 
                                         
                                      
                      
                                                                        









                                                                                     
 
/*
 * Copyright (C) 2008-2023, 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 java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.stream.IntStream;

import javax.inject.Inject;

import com.juick.model.User;
import com.juick.service.EmailService;
import com.juick.service.StorageService;
import com.juick.service.TagService;
import com.juick.service.TelegramService;
import com.juick.service.UserService;
import com.juick.service.activities.UpdateUserEvent;
import com.juick.util.HttpBadRequestException;
import com.juick.util.HttpUtils;
import com.juick.www.WebApp;

import io.swagger.v3.oas.annotations.Parameter;
import jakarta.mail.Message;
import jakarta.mail.MessagingException;
import jakarta.mail.Session;
import jakarta.mail.Transport;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
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;

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

    @Inject
    private TagService tagService;
    @Inject
    private UserService userService;
    @Inject
    private EmailService emailService;
    @Inject
    private TelegramService telegramService;
    @Inject
    private StorageService storageService;
    @Inject
    private WebApp webApp;
    @Inject
    private ApplicationEventPublisher applicationEventPublisher;

    @GetMapping("/settings")
    protected String doGet(
            @Parameter(hidden = true) User visitor,
            Locale locale,
            @RequestParam(required = false, defaultValue = "main") String page,
            @RequestParam(required = false) String code, ModelMap model) {
        visitor.setAvatar(webApp.getAvatarWebPath(visitor));
        List<String> pages = Arrays.asList("main", "password", "about", "auth-email", "privacy");
        if (!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("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")).toList();
        model.addAttribute("hours", hours);
        model.addAttribute("fbstatus", userService.getFbCrossPostStatus(visitor.getUid()));
        model.addAttribute("twitter_name", userService.getTwitterName(visitor.getUid()));
        model.addAttribute("telegram_name", userService.getTelegramName(visitor.getUid()));
        model.addAttribute("userinfo", userService.getUserInfo(visitor));
        if (page.equals("auth-email")) {
            if (emailService.verifyAddressByCode(visitor.getUid(), code)) {
                model.addAttribute("result", "OK!");
            } else {
                model.addAttribute("result", "Sorry, code unknown.");
            }
        }
        return String.format("views/settings_%s", page);
    }

    @PostMapping("/settings")
    protected String doPost(
            @Parameter(hidden = true) User visitor,
            HttpServletRequest request, HttpServletResponse response,
            @RequestParam(required = false) MultipartFile newAvatar,
            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 "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(newAvatar, storageService.getTemporaryDirectory()).getHost();
                if (StringUtils.isNotEmpty(avatarTmpPath)) {
                    storageService.saveAvatar(avatarTmpPath, visitor);
                }
                if (userService.updateUserInfo(visitor)) {
                    result = String.format("<p>Your info is updated.</p><p><a href='/%s/'>Back to blog</a>.</p>", visitor.getName());
                }
                applicationEventPublisher.publishEvent(new UpdateUserEvent(this, visitor));
                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":
                userService.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":
                if (userService.canDeleteTelegramUser(visitor)) {
                    telegramService.deleteTelegramUser(visitor.getUid());
                }
                result = "<p><a href=\"/settings\">Back</a></p>";
                break;
            case "facebook-disable":
                userService.disableFBCrosspost(visitor.getUid());
                result = "<p><a href=\"/settings\">Back</a></p>";
                break;
            case "facebook-enable":
                userService.enableFBCrosspost(visitor.getUid());
                result = "<p><a href=\"/settings\">Back</a></p>";
                break;
            case "vk-del":
                userService.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(
            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();
    }
}