/* * Copyright (C) 2008-2017, 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 . */ package com.juick.www.controllers; import com.juick.Tag; import com.juick.formatters.PlainTextFormatter; import com.juick.server.util.HttpForbiddenException; import com.juick.server.util.HttpNotFoundException; import com.juick.server.util.UserUtils; import com.juick.service.CrosspostService; import com.juick.service.MessagesService; import com.juick.service.UserService; import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.StringEscapeUtils; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; import javax.inject.Inject; import java.io.IOException; import java.util.ArrayList; import java.util.function.BooleanSupplier; import java.util.List; import java.util.stream.Collectors; /** * * @author Ugnich Anton */ @Controller public class UserThread { @Inject private MessagesService messagesService; @Inject private UserService userService; @Inject private CrosspostService crosspostService; @GetMapping("/{uname}/{mid}") protected String threadAction(ModelMap model, @PathVariable String uname, @PathVariable int mid, @RequestParam(required = false, value = "view") String paramView) throws IOException { com.juick.User visitor = UserUtils.getCurrentUser(); if (!messagesService.canViewThread(mid, visitor.getUid())) { throw new HttpForbiddenException(); } com.juick.Message msg = messagesService.getMessage(mid); if (msg == null || msg.getUser().isBanned()) { throw new HttpNotFoundException(); } com.juick.User user = userService.getUserByName(uname); if (user.getUid() == 0 || !msg.getUser().equals(user)) { return String.format("redirect:/%s/%d", msg.getUser().getName(), mid); } msg.VisitorCanComment = visitor.getUid() > 0; if (visitor.getUid() > 0) { boolean isMsgAuthor = visitor.getUid() == msg.getUser().getUid(); boolean isInBL = userService.isInBL(msg.getUser().getUid(), visitor.getUid()); msg.VisitorCanComment = isMsgAuthor || !(msg.ReadOnly || isInBL); } model.addAttribute("msg", msg); boolean listview = false; if (paramView != null) { if (paramView.equals("list")) { listview = true; if (visitor.getUid() > 0) { userService.setUserOptionInt(visitor.getUid(), "repliesview", 1); } } else if (paramView.equals("tree") && visitor.getUid() > 0) { userService.setUserOptionInt(visitor.getUid(), "repliesview", 0); } } else if (visitor.getUid() > 0 && userService.getUserOptionInt(visitor.getUid(), "repliesview", 0) == 1) { listview = true; } model.addAttribute("listview", listview); String title = msg.getUser().getName() + ": " + msg.getTagsString(); model.addAttribute("title", title); model.addAttribute("visitor", visitor); String headers = ""; String pageUrl = "https://juick.com/" + msg.getUser().getName() + "/" + msg.getMid(); if (paramView != null) { headers += ""; } if (msg.Hidden) { headers += ""; } String cardType = StringUtils.isNotEmpty(msg.getAttachmentType()) ? "summary_large_image" : "summary"; String msgImage = StringUtils.isNotEmpty(msg.getAttachmentType()) ? msg.getPhotoURLs().getMedium() : "https://i.juick.com/a/" + msg.getUser().getUid() + ".png"; model.addAttribute("ogtype", "article"); String cardDescription = StringEscapeUtils.escapeHtml4(PlainTextFormatter.formatTwitterCard(msg)); headers += "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + ""; String twitterName = crosspostService.getTwitterName(msg.getUser().getUid()); if (StringUtils.isNotEmpty(twitterName)) { headers += "\n"; } if (msg.getTags().size() > 0) { headers += "\n"; } model.addAttribute("headers", headers); model.addAttribute("contentStyle", "margin-left: 0; width: 100%"); model.addAttribute("isModerator", visitor.getUid() == 3694); model.addAttribute("visitorSubscribed", messagesService.isSubscribed(visitor.getUid(), msg.getMid())); model.addAttribute("visitorInBL", userService.isInBL(msg.getUser().getUid(), visitor.getUid())); model.addAttribute("recomm", messagesService.getMessageRecommendations(msg.getMid())); List replies = messagesService.getReplies(msg.getMid()); List blUIDs = new ArrayList<>(); for (int i = 0; i < replies.size(); i++) { com.juick.Message reply = replies.get(i); if (reply.getUser().getUid() != msg.getUser().getUid() && !blUIDs.contains(reply.getUser().getUid())) { blUIDs.add(reply.getUser().getUid()); } if (reply.getReplyto() > 0) { boolean added = false; for (int n = 0; n < replies.size(); n++) { if (replies.get(n).getRid() == reply.getReplyto()) { replies.get(n).childs.add(reply); added = true; break; } } if (!added) { reply.setReplyto(0); } } reply.VisitorCanComment = visitor.getUid() > 0; if (visitor.getUid() > 0) { boolean isMsgAuthor = visitor.getUid() == msg.getUser().getUid(); boolean isReplyAuthor = visitor.getUid() == reply.getUser().getUid(); BooleanSupplier isInBL2 = () -> userService.checkBL(visitor.getUid(), blUIDs).contains(reply.getUser().getUid()); reply.VisitorCanComment = isMsgAuthor || (!msg.ReadOnly && (isReplyAuthor || !isInBL2.getAsBoolean())); } } boolean foldable = false; if (replies.size() > 10) { for (int i = 0; i < replies.size() - 1; i++) { if (replies.get(i).getChildsCount() > 1) { foldable = true; break; } } } model.addAttribute("replies", replies); model.addAttribute("foldable", foldable); return "views/thread"; } // when message id is not fit to int @ExceptionHandler(NumberFormatException.class) public ResponseEntity notFoundAction() { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } }