Skip to content

Commit

Permalink
Revisions und Diff (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bernd Ritter committed May 24, 2024
1 parent fc6a71e commit 39e14ff
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 37 deletions.
7 changes: 6 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,12 @@
<artifactId>s3</artifactId>
<version>2.25.35</version>
</dependency>


<dependency>
<groupId>io.github.java-diff-utils</groupId>
<artifactId>java-diff-utils</artifactId>
<version>4.12</version>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.Optional;

/**
*
* @author comrad
Expand All @@ -18,4 +20,7 @@ public interface ArticleRevisionRepository extends JpaRepository<ArticleRevision
@Query("from ArticleRevision ar where ar.nodeId = :nodeId")
Page<ArticleRevision> findHistory(@Param("nodeId") final Integer nodeId, final Pageable pageable);

@Query("from ArticleRevision ar where ar.nodeId = :nodeId and ar.revision = :revisionId")
Optional<ArticleRevision> findByRevisionId(@Param("nodeId") final Integer nodeId, @Param("revisionId") final Integer revisionId);

}
11 changes: 11 additions & 0 deletions src/main/java/de/holarse/backend/view/ArticleView.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public class ArticleView {
private List<AttachmentView> websiteLinks = new ArrayList<>();
private List<YoutubeView> youtubeVideos = new ArrayList<>();
private List<ScreenshotView> screenshotViews = new ArrayList<>();

private Integer revision;

public static ArticleView of(final ArticleRevision ar, final NodeSlug slug) {
final ArticleView av = new ArticleView();
Expand All @@ -53,6 +55,7 @@ public static ArticleView of(final ArticleRevision ar, final NodeSlug slug) {
av.setContent(ar.getContent());
av.setCreated(ar.getCreated().toLocalDateTime());
av.setUpdated(ar.getUpdated().toLocalDateTime());
av.setRevision(ar.getRevision());

if (StringUtils.isNotBlank(ar.getTitle2())) { av.getAlternativeTitles().add(ar.getTitle2()); }
if (StringUtils.isNotBlank(ar.getTitle3())) { av.getAlternativeTitles().add(ar.getTitle3()); }
Expand Down Expand Up @@ -217,4 +220,12 @@ public List<ScreenshotView> getScreenshots() {
public void setScreenshots(List<ScreenshotView> screenshotViews) {
this.screenshotViews = screenshotViews;
}

public Integer getRevision() {
return revision;
}

public void setRevision(Integer revision) {
this.revision = revision;
}
}
48 changes: 47 additions & 1 deletion src/main/java/de/holarse/web/controller/RevisionController.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package de.holarse.web.controller;

import com.github.difflib.DiffUtils;
import com.github.difflib.text.DiffRow;
import com.github.difflib.text.DiffRowGenerator;
import de.holarse.backend.db.Article;
import de.holarse.backend.db.ArticleRevision;
import de.holarse.backend.db.NodeSlug;
Expand All @@ -9,6 +12,7 @@
import de.holarse.backend.types.NodeType;
import de.holarse.backend.view.ArticleView;
import de.holarse.web.defines.WebDefines;
import de.holarse.web.services.ArticleService;
import jakarta.persistence.EntityNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -21,8 +25,9 @@
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.servlet.ModelAndView;

import static de.holarse.web.defines.WebDefines.REVISION_DEFAULT_PAGE_SIZE;
import java.util.Arrays;
import java.util.List;

@Controller
public class RevisionController {
Expand All @@ -35,6 +40,9 @@ public class RevisionController {
@Autowired
private ArticleRevisionRepository articleRevisionRepository;

@Autowired
private ArticleService articleService;

@Autowired
private NodeSlugRepository nodeSlugRepository;

Expand All @@ -51,6 +59,8 @@ public ModelAndView revisions(@PathVariable final Integer nodeId, @PageableDefau
mv.addObject("view", ArticleView.of(currentArticle.getNodeRevision(), mainSlug));
mv.addObject("revisions", articleRevisionRepository.findHistory(nodeId, pageable));



return mv;
}

Expand All @@ -60,9 +70,45 @@ public ModelAndView show(@PathVariable final Integer nodeId, @PathVariable final
mv.addObject("title", "Die Linuxspiele-Seite für Linuxspieler");
mv.addObject(WebDefines.DEFAULT_VIEW_ATTRIBUTE_NAME, "sites/revisions/show");

final ArticleRevision articleRevision = articleRevisionRepository.findByRevisionId(nodeId, revision).orElseThrow(EntityNotFoundException::new);

final Article article = articleRepository.findByNodeId(nodeId).orElseThrow(EntityNotFoundException::new);
final ArticleView view = articleService.buildArticleView(article, articleRevision);

mv.addObject("nodeid", articleRevision.getNodeId());
mv.addObject("view", view);

return mv;
}

@GetMapping("/wiki/{nodeId}/revisions/view/{revision1}/{revision2}")
public ModelAndView diff(@PathVariable final Integer nodeId, @PathVariable final Integer revision1, @PathVariable final Integer revision2, final ModelAndView mv) {
mv.setViewName("layouts/bare");
mv.addObject("title", "Die Linuxspiele-Seite für Linuxspieler");
mv.addObject(WebDefines.DEFAULT_VIEW_ATTRIBUTE_NAME, "sites/revisions/diff");

final ArticleRevision articleRevision1 = articleRevisionRepository.findByRevisionId(nodeId, revision1).orElseThrow(EntityNotFoundException::new);
final ArticleRevision articleRevision2 = articleRevisionRepository.findByRevisionId(nodeId, revision2).orElseThrow(EntityNotFoundException::new);

final Article article = articleRepository.findByNodeId(nodeId).orElseThrow(EntityNotFoundException::new);

final ArticleView view1 = articleService.buildArticleView(article, articleRevision1);
final ArticleView view2 = articleService.buildArticleView(article, articleRevision2);

final DiffRowGenerator diffGenerator = DiffRowGenerator.create().showInlineDiffs(true).mergeOriginalRevised(true).inlineDiffByWord(true).oldTag(f -> "~").newTag(f -> "**").build();
final List<DiffRow> diffRows = diffGenerator.generateDiffRows(Arrays.asList(view1.getContent().split("\n")), Arrays.asList(view2.getContent().split("\n")));

final StringBuilder buffer = new StringBuilder(4096);
for (final DiffRow diffRow : diffRows) {
buffer.append(diffRow.getOldLine()).append("\n");
buffer.append(diffRow.getNewLine()).append("\n");
}

mv.addObject("nodeid", article.getNodeId());
mv.addObject("view1", view1);
mv.addObject("view2", view2);
mv.addObject("diff", buffer.toString());

return mv;
}
}
40 changes: 6 additions & 34 deletions src/main/java/de/holarse/web/controller/WikiController.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ public class WikiController {
@Autowired
private EntityLockService entityLockService;

@Autowired
private ArticleService articleService;

@Autowired
private Renderer renderer;

Expand Down Expand Up @@ -151,41 +154,10 @@ public ModelAndView show(@PathVariable("slug") final String slug, final ModelAnd

final Article article = articleRepository.findBySlug(slug).orElseThrow(EntityNotFoundException::new);
final ArticleRevision articleRevision = article.getNodeRevision();
final Set<Tag> tags = article.getTags();
final List<TagGroup> relevantTagGroups = tags.stream().map(t -> t.getTagGroup()).toList();
final NodeSlug mainSlug = nodeSlugRepository.findMainSlug(articleRevision.getNodeId(), NodeType.article).orElseThrow(EntityNotFoundException::new);

mv.addObject("nodeid", article.getNodeId());

// TODO
// if (article.getNodeStatus().isDeleted() || !article.getNodeStatus().isPublished()) {
// logger.debug("Principal: {}", principal);
// if (principal instanceof HolarsePrincipal holarsePrincipal) {
// if (holarsePrincipal.getAuthorities().stream().filter(a -> a.getAuthority().equalsIgnoreCase(RoleUserTypes.ROLE_USER_ADMIN)).count() > 0) {
// adminOverride = true;
// }
// }
//
// if (!adminOverride) {
// mv.addObject(WebDefines.DEFAULT_VIEW_ATTRIBUTE_NAME, "sites/wiki/blocked");
// return mv;
// }
// }

final List<Attachment> websiteLinks = attachmentService.getAttachments(article, attachmentGroupRepository.findByCode(AttachmentGroupType.website.name()));
final List<Attachment> videos = attachmentService.getAttachments(article, attachmentGroupRepository.findByCode(AttachmentGroupType.video.name()));
final List<Attachment> screenshots = attachmentService.getAttachments(article, attachmentGroupRepository.findByCode(AttachmentGroupType.image.name()));

// View zusammenstellen
final ArticleView view = ArticleView.of(articleRevision, mainSlug);
view.setNodeId(article.getNodeId());
view.setTagList(tags.stream().map(TagView::of).sorted(Comparator.comparingInt(TagView::getWeight).reversed().thenComparing(TagView::getUseCount).reversed().thenComparing(TagView::getName)).toList());
view.setContent(renderer.render(view.getContent(), null));
//view.setSlug(mainSlug.getName());
view.setWebsiteLinks(websiteLinks.stream().map(AttachmentView::of).toList());
view.setYoutubeVideos(videos.stream().map(YoutubeView::of).toList());
view.setScreenshots(screenshots.stream().map(ScreenshotView::of).map(ssv -> objectStorageService.patchUrl(ssv)).toList());
final ArticleView view = articleService.buildArticleView(article, articleRevision);

mv.addObject("nodeid", articleRevision.getNodeId());
mv.addObject("view", view);

return mv;
Expand Down Expand Up @@ -244,7 +216,7 @@ public ModelAndView edit(@PathVariable final Integer nodeId, final ModelAndView

return mv.addObject("form", form);
}

@Transactional
@PostMapping("{nodeId}")
public ModelAndView update(@PathVariable final int nodeId, @ModelAttribute("form") final ArticleForm form, final ModelAndView mv, final Authentication authentication) throws JsonProcessingException {
Expand Down
73 changes: 73 additions & 0 deletions src/main/java/de/holarse/web/services/ArticleService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package de.holarse.web.services;

import de.holarse.backend.db.*;
import de.holarse.backend.db.repositories.AttachmentGroupRepository;
import de.holarse.backend.db.repositories.NodeSlugRepository;
import de.holarse.backend.types.AttachmentGroupType;
import de.holarse.backend.types.NodeType;
import de.holarse.backend.view.*;
import de.holarse.web.renderer.Renderer;
import jakarta.persistence.EntityNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.List;
import java.util.Set;

@Service
public class ArticleService {

@Autowired
private AttachmentService attachmentService;

@Autowired
private ObjectStorageService objectStorageService;

@Autowired
private AttachmentGroupRepository attachmentGroupRepository;

@Autowired
private NodeSlugRepository nodeSlugRepository;

@Autowired
private Renderer renderer;

public ArticleView buildArticleView(final Article article, final ArticleRevision articleRevision) {
final Set<Tag> tags = article.getTags();
final List<TagGroup> relevantTagGroups = tags.stream().map(Tag::getTagGroup).toList();
final NodeSlug mainSlug = nodeSlugRepository.findMainSlug(articleRevision.getNodeId(), NodeType.article).orElseThrow(EntityNotFoundException::new);

// TODO
// if (article.getNodeStatus().isDeleted() || !article.getNodeStatus().isPublished()) {
// logger.debug("Principal: {}", principal);
// if (principal instanceof HolarsePrincipal holarsePrincipal) {
// if (holarsePrincipal.getAuthorities().stream().filter(a -> a.getAuthority().equalsIgnoreCase(RoleUserTypes.ROLE_USER_ADMIN)).count() > 0) {
// adminOverride = true;
// }
// }
//
// if (!adminOverride) {
// mv.addObject(WebDefines.DEFAULT_VIEW_ATTRIBUTE_NAME, "sites/wiki/blocked");
// return mv;
// }
// }

final List<Attachment> websiteLinks = attachmentService.getAttachments(article, attachmentGroupRepository.findByCode(AttachmentGroupType.website.name()));
final List<Attachment> videos = attachmentService.getAttachments(article, attachmentGroupRepository.findByCode(AttachmentGroupType.video.name()));
final List<Attachment> screenshots = attachmentService.getAttachments(article, attachmentGroupRepository.findByCode(AttachmentGroupType.image.name()));

// View zusammenstellen
final ArticleView view = ArticleView.of(articleRevision, mainSlug);
view.setNodeId(article.getNodeId());
view.setTagList(tags.stream().map(TagView::of).sorted(Comparator.comparingInt(TagView::getWeight).reversed().thenComparing(TagView::getUseCount).reversed().thenComparing(TagView::getName)).toList());
view.setContent(renderer.render(view.getContent(), null));
//view.setSlug(mainSlug.getName());
view.setWebsiteLinks(websiteLinks.stream().map(AttachmentView::of).toList());
view.setYoutubeVideos(videos.stream().map(YoutubeView::of).toList());
view.setScreenshots(screenshots.stream().map(ScreenshotView::of).map(ssv -> objectStorageService.patchUrl(ssv)).toList());

return view;
}

}
8 changes: 8 additions & 0 deletions src/main/webapp/WEB-INF/templates/sites/revisions/diff.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<section class="g-pt-50 g-pb-90">
<div class="container">
Diff zwischen Revision <div data-th-text="${view1.revision}"></div> und <div data-th-text="${view2.revision}"></div>
</div>

<div data-th-text="${diff}"></div>

</section>
5 changes: 4 additions & 1 deletion src/main/webapp/WEB-INF/templates/sites/revisions/show.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<section class="g-pt-50 g-pb-90">
<div class="container">
Revision
Revision <div data-th-text="${view.revision}"></div> von <div data-th-text="${view.title1}"></div>
</div>

<div data-th-replace="~{sites/wiki/show}"></div>

</section>
4 changes: 4 additions & 0 deletions src/main/webapp/WEB-INF/templates/sites/wiki/show.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ <h4 class="g-font-weight-200" data-th-text="${altTitle}"></h4>
<a href="?stats" class="list-group-item flex-fill">Statistik</a>
</ul>

<div>
Aktuelle Revision: <div data-th-text="${view.revision}"></div>
</div>

<div class="u-heading-v1-2 g-bg-main g-brd-primary g-mb-20">
<h2 class="h3 u-heading-v1__title">Tags</h2>
</div>
Expand Down

0 comments on commit 39e14ff

Please sign in to comment.