/* * Copyright (C) 2008-2021, 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.rss; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; import javax.inject.Inject; import com.juick.model.Attachment; import com.juick.model.Message; import com.juick.model.User; import com.juick.service.StorageService; import com.juick.util.MessageUtils; import com.juick.www.WebApp; import com.juick.www.rss.extension.JuickModule; import com.juick.www.rss.extension.JuickModuleImpl; import com.rometools.modules.atom.modules.AtomLinkModule; import com.rometools.modules.atom.modules.AtomLinkModuleImpl; import com.rometools.modules.mediarss.MediaEntryModuleImpl; import com.rometools.modules.mediarss.MediaModule; import com.rometools.modules.mediarss.MediaModuleImpl; import com.rometools.modules.mediarss.types.MediaContent; import com.rometools.modules.mediarss.types.Metadata; import com.rometools.modules.mediarss.types.Thumbnail; import com.rometools.modules.mediarss.types.UrlReference; import com.rometools.rome.feed.atom.Link; import com.rometools.rome.feed.rss.Category; import com.rometools.rome.feed.rss.Channel; import com.rometools.rome.feed.rss.Description; import com.rometools.rome.feed.rss.Guid; import com.rometools.rome.feed.rss.Image; import com.rometools.rome.feed.rss.Item; import jakarta.annotation.PostConstruct; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.servlet.view.feed.AbstractRssFeedView; /** * Created by vitalyster on 13.12.2016. */ public class MessagesView extends AbstractRssFeedView { private static final Logger logger = LoggerFactory.getLogger(Feeds.class); @Inject private StorageService storageService; @Inject private WebApp webApp; @PostConstruct public void init() { setContentType("application/rss+xml;charset=UTF-8"); } @SuppressWarnings("unchecked") @Override protected List buildFeedItems(Map model, HttpServletRequest request, HttpServletResponse response) { List msgs = (List) model.get("messages"); return msgs.stream().map(this::createRssItem).toList(); } @Override protected void buildFeedMetadata(Map model, Channel feed, HttpServletRequest request) { Object userObj = model.get("user"); String feedType = (String) model.get("feedType"); if (userObj != null) { User user = (User) userObj; if (!user.isAnonymous()) { feed.setDescription(String.format("The latest messages by @%s at Juick", user.getName())); String title = String.format("%s - Juick", user.getName()); feed.setTitle(title); String link = String.format("https://juick.com/%s/", user.getName()); feed.setLink(link); try { Attachment avatar = storageService.getAvatarMetadata(user); Image rssImage = new Image(); rssImage.setUrl(webApp.getAvatarUrl(user)); rssImage.setTitle(title); rssImage.setLink(link); rssImage.setHeight(avatar.getHeight()); rssImage.setWidth(avatar.getWidth()); feed.setImage(rssImage); } catch (IOException e) { logger.warn("Feed avatar not found for {}", user.getName()); } String href = String.format("https://rss.juick.com/%s/%s", user.getName(), feedType); AtomLinkModule atomLinkModule = new AtomLinkModuleImpl(); Link atomLink = new Link(); atomLink.setHref(href); atomLink.setType("application/rss+xml"); atomLink.setRel("self"); atomLinkModule.setLinks(Collections.singletonList(atomLink)); feed.getModules().add(atomLinkModule); } else { feed.setDescription("The latest messages at Juick"); feed.setLink("https://juick.com/"); feed.setTitle("Juick"); } } MediaModule mediaModule = new MediaModuleImpl(); feed.getModules().add(mediaModule); } private Item createRssItem(Message msg) { Item item = new Item(); String messageUrl = String.format("https://juick.com/%s/%d", msg.getUser().getName(), msg.getMid()); String messageTitle = String.format("@%s: %s", msg.getUser().getName(), MessageUtils.getTagsString(msg)); boolean isCode = msg.getTags().stream().anyMatch(t -> t.getName().equals("code")); String messageDescription = isCode ? MessageUtils.formatMessageCode(StringUtils.defaultString(msg.getText())) : MessageUtils.formatMessage(StringUtils.defaultString(msg.getText())); item.setLink(messageUrl); Guid guid = new Guid(); guid.setPermaLink(true); guid.setValue(messageUrl); item.setGuid(guid); item.setTitle(messageTitle); Description description = new Description(); description.setType("text/html"); description.setValue(messageDescription); item.setDescription(description); item.setPubDate(Date.from(msg.getCreated())); item.setComments(messageUrl); msg.getTags().stream().map(t -> { Category category = new Category(); category.setValue(t.getName()); return category; }).forEach(c -> item.getCategories().add(c)); JuickModule juickModule = new JuickModuleImpl(); juickModule.setUid(msg.getUser().getUid()); item.getModules().add(juickModule); if (StringUtils.isNotEmpty(msg.getAttachmentType())) { String type = msg.getAttachmentType().equals("jpg") ? "image/jpeg" : "image/png"; MediaEntryModuleImpl module = new MediaEntryModuleImpl(); try { UrlReference reference = new UrlReference(MessageUtils.attachmentUrl(msg)); MediaContent mediaContent = new MediaContent(reference); mediaContent.setType(type); Metadata metadata = new Metadata(); metadata.setThumbnail(new Thumbnail[] { new Thumbnail(new URI(msg.getPhoto().getThumbnail())) }); module.setMetadata(metadata); module.setMediaContents(new MediaContent[] { mediaContent }); item.getModules().add(module); } catch (URISyntaxException e) { logger.error("Invalid URI", e); } } return item; } }