Search in sources :

Example 1 with PublicPage

use of org.moera.node.data.PublicPage in project moera-node by MoeraOrg.

the class PublicPageOperations method createPagination.

public List<PaginationItem> createPagination(PublicPage page) {
    if (page == null) {
        return null;
    }
    UUID entryId = page.getEntry() != null ? page.getEntry().getId() : null;
    int current = countNumber(entryId, page.getBeforeMoment());
    int last = countTotal(entryId);
    if (last <= 1) {
        return null;
    }
    int tillLast = last - current;
    tillLast = Math.min(tillLast, 2);
    int rangeFirst = current + tillLast - 4;
    rangeFirst = Math.max(rangeFirst, 1);
    PublicPage firstPage = findPages(entryId, null, rangeFirst - 1, 1).getContent().get(0);
    PublicPage lastPage = findPages(entryId, null, last - 1, 1).getContent().get(0);
    List<PublicPage> pages = findPages(entryId, firstPage.getBeforeMoment(), 0, 5).getContent();
    int rangeLast = rangeFirst + pages.size() - 1;
    LinkedList<PaginationItem> items = new LinkedList<>();
    for (int i = 0; i < pages.size(); i++) {
        items.add(PaginationItem.pageLink(rangeFirst + i, pages.get(i).getBeforeMoment(), rangeFirst + i == current));
    }
    if (rangeFirst > 2) {
        items.addFirst(PaginationItem.pageDots());
    }
    if (rangeFirst > 1) {
        items.addFirst(PaginationItem.pageLink(1, firstPage.getBeforeMoment(), false));
    }
    if (last - rangeLast > 1) {
        items.addLast(PaginationItem.pageDots());
    }
    if (last > rangeLast) {
        items.addLast(PaginationItem.pageLink(last, lastPage.getBeforeMoment(), false));
    }
    long prevMoment = 0;
    long nextMoment = 0;
    boolean afterCurrent = false;
    for (PaginationItem item : items) {
        if (item.isDots()) {
            continue;
        }
        if (item.isActive()) {
            afterCurrent = true;
            continue;
        }
        if (!afterCurrent) {
            prevMoment = item.getMoment();
        } else {
            nextMoment = item.getMoment();
            break;
        }
    }
    if (prevMoment != 0) {
        items.addFirst(PaginationItem.pageLink("← Previous", prevMoment, false));
    }
    if (nextMoment != 0) {
        items.addLast(PaginationItem.pageLink("Next →", nextMoment, false));
    }
    return items;
}
Also used : PaginationItem(org.moera.node.ui.PaginationItem) UUID(java.util.UUID) PublicPage(org.moera.node.data.PublicPage) LinkedList(java.util.LinkedList)

Example 2 with PublicPage

use of org.moera.node.data.PublicPage in project moera-node by MoeraOrg.

the class PublicPageOperations method updatePublicPages.

protected void updatePublicPages(UUID entryId, long moment) {
    PublicPage firstPage = findByBeforeMoment(entryId, Long.MAX_VALUE);
    if (firstPage == null) {
        firstPage = new PublicPage();
        firstPage.setNodeId(requestContext.nodeId());
        firstPage.setEntry(findEntryById(entryId));
        firstPage.setAfterMoment(Long.MIN_VALUE);
        firstPage.setBeforeMoment(Long.MAX_VALUE);
        publicPageRepository.save(firstPage);
        return;
    }
    long after = firstPage.getAfterMoment();
    if (moment > after) {
        int count = countInRange(entryId, after, Long.MAX_VALUE);
        if (count >= publicPageMaxSize) {
            long median = findMomentsInRange(entryId, after, Long.MAX_VALUE, PageRequest.of(count - publicPageAvgSize, 1, Sort.by(Sort.Direction.DESC, "moment"))).getContent().get(0);
            firstPage.setAfterMoment(median);
            PublicPage secondPage = new PublicPage();
            secondPage.setNodeId(requestContext.nodeId());
            secondPage.setEntry(findEntryById(entryId));
            secondPage.setAfterMoment(after);
            secondPage.setBeforeMoment(median);
            publicPageRepository.save(secondPage);
        }
        return;
    }
    PublicPage lastPage = findByAfterMoment(entryId, Long.MIN_VALUE);
    long end = lastPage.getBeforeMoment();
    if (moment <= end) {
        int count = countInRange(entryId, Long.MIN_VALUE, end);
        if (count >= publicPageMaxSize) {
            long median = findMomentsInRange(entryId, Long.MIN_VALUE, end, PageRequest.of(publicPageAvgSize + 1, 1, Sort.by(Sort.Direction.DESC, "moment"))).getContent().get(0);
            lastPage.setBeforeMoment(median);
            PublicPage prevPage = new PublicPage();
            prevPage.setNodeId(requestContext.nodeId());
            prevPage.setEntry(findEntryById(entryId));
            prevPage.setAfterMoment(median);
            prevPage.setBeforeMoment(end);
            publicPageRepository.save(prevPage);
        }
    }
}
Also used : PublicPage(org.moera.node.data.PublicPage)

Example 3 with PublicPage

use of org.moera.node.data.PublicPage in project moera-node by MoeraOrg.

the class RssController method rss.

@GetMapping("/rss")
@Transactional
@ResponseBody
public SyndFeed rss() {
    RequestContext rcp = requestContext.getPublic();
    PublicPage publicPage = publicPageRepository.findContaining(rcp.nodeId(), Long.MAX_VALUE);
    List<Story> stories = Collections.emptyList();
    if (publicPage != null) {
        stories = storyRepository.findInRange(rcp.nodeId(), Feed.TIMELINE, publicPage.getAfterMoment(), publicPage.getBeforeMoment()).stream().filter(t -> t.getEntry().isMessage()).sorted(Collections.reverseOrder(Comparator.comparingLong(Story::getMoment))).collect(Collectors.toList());
    }
    SyndFeed feed = new SyndFeedImpl();
    feed.setFeedType("rss_2.0");
    String name = rcp.fullName() != null ? rcp.fullName() : rcp.nodeName();
    String title = !ObjectUtils.isEmpty(name) ? name + " - Moera" : "Moera";
    feed.setTitle(title);
    feed.setLink(rcp.getSiteUrl() + "/");
    if (rcp.avatarId() != null) {
        SyndImage image = new SyndImageImpl();
        image.setTitle(title);
        image.setUrl(rcp.getSiteUrl() + "/moera/media/" + new AvatarImage(rcp.getAvatar()).getPath());
        image.setLink(rcp.getSiteUrl() + "/");
        feed.setImage(image);
    }
    feed.setDescription(title);
    feed.setLanguage("en-us");
    feed.setPublishedDate(!stories.isEmpty() ? stories.get(0).getCreatedAt() : Util.now());
    feed.setGenerator("moera-node");
    feed.setWebMaster(buildWebmaster());
    feed.setEntries(stories.stream().map(this::buildEntry).collect(Collectors.toList()));
    return feed;
}
Also used : SyndEntryImpl(com.rometools.rome.feed.synd.SyndEntryImpl) Util(org.moera.node.util.Util) SyndFeedImpl(com.rometools.rome.feed.synd.SyndFeedImpl) Inject(javax.inject.Inject) Story(org.moera.node.data.Story) StoryRepository(org.moera.node.data.StoryRepository) SyndImage(com.rometools.rome.feed.synd.SyndImage) SyndFeed(com.rometools.rome.feed.synd.SyndFeed) GetMapping(org.springframework.web.bind.annotation.GetMapping) SyndContentImpl(com.rometools.rome.feed.synd.SyndContentImpl) Transactional(javax.transaction.Transactional) Feed(org.moera.node.data.Feed) EntryRevision(org.moera.node.data.EntryRevision) SyndEntry(com.rometools.rome.feed.synd.SyndEntry) ObjectUtils(org.springframework.util.ObjectUtils) PublicPageRepository(org.moera.node.data.PublicPageRepository) SyndContent(com.rometools.rome.feed.synd.SyndContent) Entry(org.moera.node.data.Entry) RequestContext(org.moera.node.global.RequestContext) SyndImageImpl(com.rometools.rome.feed.synd.SyndImageImpl) ResponseBody(org.springframework.web.bind.annotation.ResponseBody) Collectors(java.util.stream.Collectors) RestController(org.springframework.web.bind.annotation.RestController) AvatarImage(org.moera.node.model.AvatarImage) List(java.util.List) PublicPage(org.moera.node.data.PublicPage) Comparator(java.util.Comparator) Collections(java.util.Collections) SyndFeed(com.rometools.rome.feed.synd.SyndFeed) SyndImageImpl(com.rometools.rome.feed.synd.SyndImageImpl) SyndImage(com.rometools.rome.feed.synd.SyndImage) SyndFeedImpl(com.rometools.rome.feed.synd.SyndFeedImpl) RequestContext(org.moera.node.global.RequestContext) PublicPage(org.moera.node.data.PublicPage) AvatarImage(org.moera.node.model.AvatarImage) Story(org.moera.node.data.Story) GetMapping(org.springframework.web.bind.annotation.GetMapping) Transactional(javax.transaction.Transactional) ResponseBody(org.springframework.web.bind.annotation.ResponseBody)

Example 4 with PublicPage

use of org.moera.node.data.PublicPage in project moera-node by MoeraOrg.

the class TimelineUiController method timeline.

@GetMapping("/timeline")
@VirtualPage
@Transactional
public String timeline(@RequestParam(required = false) Long before, HttpServletResponse response, Model model) {
    String canonicalUrl = "/timeline" + (before != null ? "?before=" + before : "");
    before = before != null ? before : Long.MAX_VALUE;
    List<StoryInfo> stories = Collections.emptyList();
    PublicPage publicPage = publicPageRepository.findContaining(requestContext.nodeId(), before);
    if (publicPage != null) {
        stories = storyRepository.findInRange(requestContext.nodeId(), Feed.TIMELINE, publicPage.getAfterMoment(), publicPage.getBeforeMoment()).stream().filter(t -> t.getEntry().isMessage()).map(s -> StoryInfo.build(s, false, t -> PostingInfo.forUi((Posting) t.getEntry()))).sorted(Comparator.comparing(StoryInfo::getMoment).reversed()).collect(Collectors.toList());
    }
    model.addAttribute("pageTitle", titleBuilder.build("Timeline"));
    model.addAttribute("menuIndex", "timeline");
    model.addAttribute("canonicalUrl", canonicalUrl);
    model.addAttribute("anchor", "m" + before);
    model.addAttribute("stories", stories);
    model.addAttribute("pagination", timelinePublicPageOperations.createPagination(publicPage));
    model.addAttribute("ogUrl", requestContext.getSiteUrl());
    return "timeline";
}
Also used : PathVariable(org.springframework.web.bind.annotation.PathVariable) UriComponentsBuilder(org.springframework.web.util.UriComponentsBuilder) PageNotFoundException(org.moera.node.global.PageNotFoundException) RequestParam(org.springframework.web.bind.annotation.RequestParam) StoryInfo(org.moera.node.model.StoryInfo) PostingInfo(org.moera.node.model.PostingInfo) CommentPublicPageOperations(org.moera.node.operations.CommentPublicPageOperations) Posting(org.moera.node.data.Posting) Inject(javax.inject.Inject) Story(org.moera.node.data.Story) StoryRepository(org.moera.node.data.StoryRepository) Model(org.springframework.ui.Model) TimelinePublicPageOperations(org.moera.node.operations.TimelinePublicPageOperations) GetMapping(org.springframework.web.bind.annotation.GetMapping) Body(org.moera.node.model.body.Body) Comment(org.moera.node.data.Comment) CommentInfo(org.moera.node.model.CommentInfo) Transactional(javax.transaction.Transactional) Feed(org.moera.node.data.Feed) NamingCache(org.moera.node.naming.NamingCache) ObjectUtils(org.springframework.util.ObjectUtils) HttpServletResponse(javax.servlet.http.HttpServletResponse) UiController(org.moera.node.global.UiController) PublicPageRepository(org.moera.node.data.PublicPageRepository) Entry(org.moera.node.data.Entry) UUID(java.util.UUID) RequestContext(org.moera.node.global.RequestContext) Collectors(java.util.stream.Collectors) PostingRepository(org.moera.node.data.PostingRepository) VirtualPage(org.moera.node.global.VirtualPage) AvatarImage(org.moera.node.model.AvatarImage) Objects(java.util.Objects) List(java.util.List) CommentRepository(org.moera.node.data.CommentRepository) EntryAttachment(org.moera.node.data.EntryAttachment) VirtualPageHeader(org.moera.node.util.VirtualPageHeader) PrivateMediaFileInfo(org.moera.node.model.PrivateMediaFileInfo) PublicPage(org.moera.node.data.PublicPage) Comparator(java.util.Comparator) Collections(java.util.Collections) StoryInfo(org.moera.node.model.StoryInfo) Posting(org.moera.node.data.Posting) PublicPage(org.moera.node.data.PublicPage) GetMapping(org.springframework.web.bind.annotation.GetMapping) VirtualPage(org.moera.node.global.VirtualPage) Transactional(javax.transaction.Transactional)

Example 5 with PublicPage

use of org.moera.node.data.PublicPage in project moera-node by MoeraOrg.

the class TimelineUiController method posting.

@GetMapping("/post/{id}")
@Transactional
public String posting(@PathVariable UUID id, @RequestParam(required = false) Long before, @RequestParam(name = "comment", required = false) UUID commentId, @RequestParam(name = "media", required = false) UUID mediaId, HttpServletResponse response, Model model) {
    UriComponentsBuilder builder = UriComponentsBuilder.fromPath("/post/" + id);
    if (commentId != null) {
        builder = builder.queryParam("comment", commentId);
    }
    String canonicalUrl = builder.build().toUriString();
    if (mediaId != null) {
        builder = builder.queryParam("media", mediaId);
    }
    VirtualPageHeader.put(response, builder.build().toUriString());
    if (requestContext.isBrowserExtension()) {
        return null;
    }
    Posting posting = postingRepository.findFullByNodeIdAndId(requestContext.nodeId(), id).orElse(null);
    if (posting == null || !posting.isMessage() || posting.getParentMedia() != null) {
        throw new PageNotFoundException();
    }
    List<Story> stories = storyRepository.findByEntryId(requestContext.nodeId(), id);
    model.addAttribute("pageTitle", titleBuilder.build(posting.getCurrentRevision().getHeading()));
    model.addAttribute("menuIndex", "timeline");
    model.addAttribute("posting", PostingInfo.forUi(posting, stories));
    model.addAttribute("canonicalUrl", canonicalUrl);
    model.addAttribute("openComments", commentId != null || before != null);
    model.addAttribute("openMediaPostingId", id.toString());
    model.addAttribute("openMediaCommentId", commentId != null ? commentId.toString() : null);
    model.addAttribute("openMediaId", Objects.toString(mediaId, null));
    Comment comment = commentId != null && posting.isOriginal() ? commentRepository.findFullByNodeIdAndId(requestContext.nodeId(), commentId).orElse(null) : null;
    if (posting.isOriginal()) {
        before = comment != null ? comment.getMoment() : before;
        before = before != null ? before : Long.MIN_VALUE + 1;
        List<CommentInfo> comments = Collections.emptyList();
        PublicPage publicPage = publicPageRepository.findContainingForEntry(requestContext.nodeId(), id, before);
        if (publicPage != null) {
            comments = commentRepository.findInRange(requestContext.nodeId(), id, publicPage.getAfterMoment(), publicPage.getBeforeMoment()).stream().filter(Comment::isMessage).map(CommentInfo::forUi).sorted(Comparator.comparing(CommentInfo::getMoment)).collect(Collectors.toList());
        }
        if (commentId != null) {
            model.addAttribute("anchor", "comment-" + commentId);
        }
        model.addAttribute("comments", comments);
        model.addAttribute("commentId", Objects.toString(commentId, null));
        model.addAttribute("pagination", commentPublicPageOperations.createPagination(publicPage));
    } else {
        model.addAttribute("originalHref", NamingCache.getRedirector(posting.getReceiverName(), entryLocation(posting.getReceiverEntryId(), null)));
        model.addAttribute("commentsHref", NamingCache.getRedirector(posting.getReceiverName(), entryLocation(posting.getReceiverEntryId(), commentId)));
    }
    model.addAttribute("ogUrl", requestContext.getSiteUrl() + entryLocation(posting.getId(), commentId));
    model.addAttribute("ogType", "article");
    Entry entry = comment != null ? comment : posting;
    String subject = new Body(entry.getCurrentRevision().getBody()).getSubject();
    model.addAttribute("ogTitle", !ObjectUtils.isEmpty(subject) ? subject : "(no title)");
    EntryAttachment attachment = entry.getCurrentRevision().getAttachments().stream().sorted(Comparator.comparingInt(EntryAttachment::getOrdinal)).filter(ea -> mediaId == null || ea.getMediaFileOwner().getId().equals(mediaId)).filter(// an image
    ea -> ea.getMediaFileOwner().getMediaFile().getSizeX() != null).findFirst().orElse(null);
    if (attachment != null) {
        PrivateMediaFileInfo image = new PrivateMediaFileInfo(attachment.getMediaFileOwner(), posting.getReceiverName());
        model.addAttribute("ogImage", requestContext.getSiteUrl() + "/moera/media/" + image.getPath());
        model.addAttribute("ogImageType", attachment.getMediaFileOwner().getMediaFile().getMimeType());
        model.addAttribute("ogImageWidth", image.getWidth());
        model.addAttribute("ogImageHeight", image.getHeight());
    } else if (entry.getOwnerAvatarMediaFile() != null) {
        AvatarImage avatarImage = new AvatarImage(entry.getOwnerAvatarMediaFile(), entry.getOwnerAvatarShape());
        model.addAttribute("ogImage", requestContext.getSiteUrl() + "/moera/media/" + avatarImage.getPath());
        model.addAttribute("ogImageType", avatarImage.getMediaFile().getMimeType());
        model.addAttribute("ogImageWidth", avatarImage.getWidth());
        model.addAttribute("ogImageHeight", avatarImage.getHeight());
    }
    String description = entry.getCurrentRevision().getDescription();
    description = !ObjectUtils.isEmpty(description) ? description : entry.getCurrentRevision().getHeading();
    model.addAttribute("ogDescription", description);
    var createdAt = entry.getReceiverCreatedAt() != null ? entry.getReceiverCreatedAt() : entry.getCreatedAt();
    model.addAttribute("ogArticlePublishedTime", createdAt.toInstant().toString());
    if (entry.getEditedAt() != null) {
        var editedAt = entry.getReceiverEditedAt() != null ? entry.getReceiverEditedAt() : entry.getEditedAt();
        model.addAttribute("ogArticleModifiedTime", editedAt.toInstant().toString());
    }
    return "posting";
}
Also used : PathVariable(org.springframework.web.bind.annotation.PathVariable) UriComponentsBuilder(org.springframework.web.util.UriComponentsBuilder) PageNotFoundException(org.moera.node.global.PageNotFoundException) RequestParam(org.springframework.web.bind.annotation.RequestParam) StoryInfo(org.moera.node.model.StoryInfo) PostingInfo(org.moera.node.model.PostingInfo) CommentPublicPageOperations(org.moera.node.operations.CommentPublicPageOperations) Posting(org.moera.node.data.Posting) Inject(javax.inject.Inject) Story(org.moera.node.data.Story) StoryRepository(org.moera.node.data.StoryRepository) Model(org.springframework.ui.Model) TimelinePublicPageOperations(org.moera.node.operations.TimelinePublicPageOperations) GetMapping(org.springframework.web.bind.annotation.GetMapping) Body(org.moera.node.model.body.Body) Comment(org.moera.node.data.Comment) CommentInfo(org.moera.node.model.CommentInfo) Transactional(javax.transaction.Transactional) Feed(org.moera.node.data.Feed) NamingCache(org.moera.node.naming.NamingCache) ObjectUtils(org.springframework.util.ObjectUtils) HttpServletResponse(javax.servlet.http.HttpServletResponse) UiController(org.moera.node.global.UiController) PublicPageRepository(org.moera.node.data.PublicPageRepository) Entry(org.moera.node.data.Entry) UUID(java.util.UUID) RequestContext(org.moera.node.global.RequestContext) Collectors(java.util.stream.Collectors) PostingRepository(org.moera.node.data.PostingRepository) VirtualPage(org.moera.node.global.VirtualPage) AvatarImage(org.moera.node.model.AvatarImage) Objects(java.util.Objects) List(java.util.List) CommentRepository(org.moera.node.data.CommentRepository) EntryAttachment(org.moera.node.data.EntryAttachment) VirtualPageHeader(org.moera.node.util.VirtualPageHeader) PrivateMediaFileInfo(org.moera.node.model.PrivateMediaFileInfo) PublicPage(org.moera.node.data.PublicPage) Comparator(java.util.Comparator) Collections(java.util.Collections) Comment(org.moera.node.data.Comment) Posting(org.moera.node.data.Posting) CommentInfo(org.moera.node.model.CommentInfo) PublicPage(org.moera.node.data.PublicPage) PrivateMediaFileInfo(org.moera.node.model.PrivateMediaFileInfo) PageNotFoundException(org.moera.node.global.PageNotFoundException) Entry(org.moera.node.data.Entry) UriComponentsBuilder(org.springframework.web.util.UriComponentsBuilder) EntryAttachment(org.moera.node.data.EntryAttachment) AvatarImage(org.moera.node.model.AvatarImage) Story(org.moera.node.data.Story) Body(org.moera.node.model.body.Body) GetMapping(org.springframework.web.bind.annotation.GetMapping) Transactional(javax.transaction.Transactional)

Aggregations

PublicPage (org.moera.node.data.PublicPage)5 Collections (java.util.Collections)3 Comparator (java.util.Comparator)3 List (java.util.List)3 UUID (java.util.UUID)3 Collectors (java.util.stream.Collectors)3 Inject (javax.inject.Inject)3 Transactional (javax.transaction.Transactional)3 Entry (org.moera.node.data.Entry)3 Feed (org.moera.node.data.Feed)3 PublicPageRepository (org.moera.node.data.PublicPageRepository)3 Story (org.moera.node.data.Story)3 StoryRepository (org.moera.node.data.StoryRepository)3 RequestContext (org.moera.node.global.RequestContext)3 AvatarImage (org.moera.node.model.AvatarImage)3 ObjectUtils (org.springframework.util.ObjectUtils)3 GetMapping (org.springframework.web.bind.annotation.GetMapping)3 Objects (java.util.Objects)2 HttpServletResponse (javax.servlet.http.HttpServletResponse)2 Comment (org.moera.node.data.Comment)2