package com.aperture_software.glados_wiki.webmvc.controllers; import com.aperture_software.glados_wiki.entities.*; import com.aperture_software.glados_wiki.entities.functions.page_content.PageContentToPageContentResponseFunction; import com.aperture_software.glados_wiki.entities.page_content.PageContentResponse; import com.aperture_software.glados_wiki.entities.page_content.PageContentVersionsResponse; import com.aperture_software.glados_wiki.exceptions.PageAclException; import com.aperture_software.glados_wiki.markdown.VarInLinkExpandLinkRefTransformer; import com.aperture_software.glados_wiki.markdown.WikiLinkToMarkdownFunction; import com.aperture_software.glados_wiki.markdown.WikiSignatureEscapeFunction; import com.aperture_software.glados_wiki.markdown.WikiSignatureExpandFunction; import com.aperture_software.glados_wiki.services.*; import com.aperture_software.glados_wiki.servlets.WebappPath; import com.aperture_software.glados_wiki.support.*; import com.aperture_software.glados_wiki.webmvc.controllers.helpers.RedirectHelper; import com.google.common.base.Optional; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import org.apache.shiro.authz.annotation.RequiresUser; import org.bson.types.ObjectId; import org.markdown4j.Markdown4jProcessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.View; import org.springframework.web.servlet.mvc.support.RedirectAttributesModelMap; import javax.inject.Inject; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * Created with IntelliJ IDEA. * User: jhyun * Date: 13. Nov. 18. * Time: 20:39 */ @Controller public class PageController { private static Logger LOG = LoggerFactory.getLogger(PageController.class); @Autowired private PageService pageService; @Autowired private PageContentService pageContentService; @Autowired private GroupService groupService; @Autowired private UserService userService; @Autowired private PageAclService pageAclService; @Autowired private TimeZoneService timeZoneService; @Inject private FlashAlerts flashAlerts; @Inject private RedirectHelper redirectHelper; @RequiresUser @RequestMapping(value = "/edit/{title:.+}", method = {RequestMethod.GET}) public ModelAndView editPage(@PathVariable("title") final String title , @RequestParam(value = "origVersion", defaultValue = "", required = false) final String origVersion , ModelMap m) throws PageAclException { Optional<Page> p = pageService.getPageByTitle(title); if (p.isPresent()) { Page p2 = p.get(); m.put("page", p2); m.put("title", p2.getTitle()); // check-acl pageAclService.checkWritable(p2); } else { m.put("page", null); m.put("title", title); // check-acl pageAclService.checkWritable(null); } // m.put("origVersion", origVersion); return new ModelAndView("page/edit", m); } @RequiresUser @RequestMapping(value = "/post", method = {RequestMethod.POST}) public View savePage(RedirectAttributesModelMap redirectAttributesModelMap, @RequestParam(value = "title", required = true) final String title, @RequestParam(value = "content", required = true) final String content, @RequestParam(value = "aclForEveryone", required = false, defaultValue = "") final String aclForEveryone, @RequestParam(value = "aclRUser", required = false) List<String> aclRUser, @RequestParam(value = "aclWUser", required = false) List<String> aclWUser, @RequestParam(value = "aclRGroup", required = false) List<String> aclRGroup, @RequestParam(value = "aclWGroup", required = false) List<String> aclWGroup, @RequestParam(value = "tag", required = false) List<String> tags, @RequestParam(value = "origVersion", defaultValue = "", required = false) final String origVersion ) throws Exception { // boolean jumped = false; PageContent pageContentParent = null; Page p = null; if (pageService.existsByTitle(title)) { p = pageService.getPageByTitle(title).get(); // check-acl pageAclService.checkWritable(p); // ObjectId origVersion_ = new ObjectId(origVersion); if (false == p.getCurrent().getId().equals(origVersion_)) { jumped = true; flashAlerts.add(redirectAttributesModelMap, new FlashAlerts.FlashAlert(BootstrapAlertTypes.WARNING, "Page Content has JUMPED! (maybe there's unmerged changes, check page versions.)")); Optional<PageContent> pageContentParent_ = pageContentService.load(origVersion_); if (pageContentParent_.isPresent()) { pageContentParent = pageContentParent_.get(); } else { LOG.warn(String.format("MISSING PARENT!!! -- parent=[%s], SKIP.", origVersion_.toString())); } } else { pageContentParent = p.getCurrent(); } } else { // check-acl pageAclService.checkWritable(null); // p = pageService.createByTitle(title); } // PageContent pageContent = new PageContent(); pageContent.setContent(content); pageContent.setCtime(new Date()); pageContent.setPage(p); if (pageContentParent != null) { pageContent.setParent(pageContentParent); } Optional<User> u = SecurityUtils2.getUser(userService); if (u.isPresent()) { pageContent.setCreator(u.get()); } // WikiSignatureExpandFunction wikiSignatureExpandFunction = new WikiSignatureExpandFunction(timeZoneService, u); pageContent.setContent(wikiSignatureExpandFunction.apply(pageContent.getContent())); // pageContentService.save(pageContent); // pageService.addContent(pageContent); p.setCurrent(pageContent); // p.setAclForEveryone(aclForEveryone); p.setReadables(gatherUserAuthentications(aclRGroup, aclRUser)); p.setWritables(gatherUserAuthentications(aclWGroup, aclWUser)); setPageTags(p, tags); // pageService.update(p); // return redirectHelper.redirectToPageView(title); } private void setPageTags(Page p, List<String> tags) throws Exception { if (tags != null) { for (String t : tags) { if (Strings.isNullOrEmpty(t)) { throw new Exception("EMPTY TAG IS NOT ALLOWED!"); } } p.setTags(tags); } else { p.setTags(null); } } private List<UserAuthentication> gatherUserAuthentications(List<String> groupNames, List<String> userNames) { List<UserAuthentication> results = new ArrayList<UserAuthentication>(); // if (groupNames != null) { for (String groupName : groupNames) { Optional<Group> g = groupService.getByName(groupName); if (g.isPresent()) { results.add(g.get()); } else { LOG.warn(String.format("group %s not found, skip.", groupName)); } } } if (userNames != null) { for (String userName : userNames) { Optional<User> u = userService.getByUsername(userName); if (u.isPresent()) { results.add(u.get()); } else { LOG.warn(String.format("user %s not found, skip.", userName)); } } } // return results; } @RequestMapping(value = "/pageById/{id}") public View viewPageById(@PathVariable("id") final String id) throws Exception { Optional<Page> p = pageService.getById(id); if (p.isPresent()) { return redirectHelper.redirectToPageView(p.get().getTitle()); } else { throw new Exception(String.format("PAGE-ID [%s] NOT FOUND.", id)); } } @RequestMapping(value = "/pageById2/{id}/{version}") public View viewPageById(@PathVariable("id") final String id, @PathVariable("version") final String version) throws Exception { Optional<Page> p = pageService.getById(id); if (p.isPresent()) { return redirectHelper.redirectToPageView(p.get().getTitle(), version); } else { throw new Exception(String.format("PAGE-ID [%s] NOT FOUND.", id)); } } @RequestMapping(value = "/page/{title:.+}", method = {RequestMethod.GET}) public ModelAndView viewPage(@PathVariable("title") final String title, @RequestParam(value = "version", defaultValue = "", required = false) final String versionId, ModelMap m) throws Exception { // Optional<Page> page = pageService.getPageByTitle(title); if (page.isPresent() == false) { return new ModelAndView(redirectHelper.redirectToEditPage(title)); } else { // check-acl pageAclService.checkReadable(page.get()); // m.put("page", page.get()); PageContent pageContent = getPageContent(title, versionId, page); m.put("pageContent", pageContent); // String markdowned = renderMarkdown(pageContent); m.put("markdowned", markdowned); // List<Page> tagAssocs = pageService.listTagAssocs(page.get(), 0, Integer.MAX_VALUE); m.put("tagAssocs", tagAssocs); // boolean pageWritable = pageAclService.isWritable(page.get()); m.put("pageWritable", pageWritable); // return new ModelAndView("page/view", m); } } private PageContent getPageContent(String title, String versionId, Optional<Page> page) throws Exception { PageContent pageContent; if (Strings.isNullOrEmpty(versionId)) { return page.get().getCurrent(); } else { Optional<PageContent> pc = getVersion(page.get(), versionId); if (pc.isPresent()) { return pc.get(); } else { throw new Exception(String.format("VERSION [%s] NOT FOUND FOR PAGE [%s]", versionId, title)); } } } private String renderMarkdown(PageContent pageContent) throws IOException { Markdown4jProcessor p = new Markdown4jProcessor(); p.addLinkRefTransformer(new VarInLinkExpandLinkRefTransformer( ImmutableMap.<String, String>builder() .put("WEBAPP_PATH_ROOT", WebappPath.getWebappPath()) .put("FILE", String.format("%s/a/file/blob", WebappPath.getWebappPath())) .build())); String content = pageContent.getContent(); WikiLinkToMarkdownFunction wikiLinkToMarkdownFunction = new WikiLinkToMarkdownFunction(); String content2 = wikiLinkToMarkdownFunction.apply(content); WikiSignatureEscapeFunction wikiSignatureEscapeFunction = new WikiSignatureEscapeFunction(); return p.process(wikiSignatureEscapeFunction.apply(content2)); } @ResponseBody @RequestMapping(value = "/versions/{title:.+}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public PageContentVersionsResponse listVersions(@PathVariable("title") final String title, @RequestParam(value = "offset", defaultValue = "0", required = false) int offset, @RequestParam(value = "limit", defaultValue = "25", required = false) int limit) throws Exception { // Page p2 = getPageByTitle(title); // check-acl pageAclService.checkReadable(p2); // final long tot = pageContentService.countVersions(p2); // Pagination pagination = new Pagination(tot, offset, limit); List<PageContent> l = pageContentService.listVersions(p2, offset, limit); List<PageContentResponse> l2 = Lists.transform(l, new PageContentToPageContentResponseFunction()); // return new PageContentVersionsResponse(pagination, l2); } private Optional<PageContent> getVersion(final Page page, final String versionId) { ObjectId versionId_ = new ObjectId(versionId); for (PageContent pageContent : page.getVersions()) { if (pageContent.getId().equals(versionId_)) { return Optional.of(pageContent); } } // return Optional.absent(); } @ResponseBody @RequestMapping(value = "/raw/{title:.+}", produces = MediaType.TEXT_PLAIN_VALUE + Utf8.FOR_CONTENT_TYPE) public String viewRawVersion(@PathVariable("title") final String title, @RequestParam(value = "version", defaultValue = "", required = false) final String versionId) throws Exception { // Page p2 = getPageByTitle(title); // check-acl pageAclService.checkReadable(p2); String s = null; if (Strings.isNullOrEmpty(versionId)) { s = p2.getCurrent().getContent(); } else { Optional<PageContent> c = getVersion(p2, versionId); if (c.isPresent() == false) { throw new Exception(String.format("page content for [%s] at version [%s], NOT FOUND!", title, versionId)); } s = c.get().getContent(); } // return s; } private Page getPageByTitle(String title) throws Exception { Optional<Page> p = pageService.getPageByTitle(title); if (p.isPresent() == false) { throw new Exception(String.format("Page NOT FOUND! [%s]", title)); } return p.get(); } @RequestMapping(value = "/renamePage") public View renamePage(@RequestParam(value = "pageTitle", required = true) final String pageTitle, @RequestParam(value = "newPageTitle", required = true) final String newPageTitle) throws Exception { Page p2 = getPageByTitle(pageTitle); pageAclService.checkWritable(p2); // pageService.rename(p2, newPageTitle); return redirectHelper.redirectToPageView(newPageTitle); } private void checkVersionFound(final Optional<PageContent> version, final String versionId, final Page p) throws Exception { if (version.isPresent() == false) { throw new Exception(String.format("VERSION [%s] FOR PAGE [%s] NOT FOUND!", versionId, p.getTitle())); } } @RequestMapping(value = "/diff/{title:.+}") public ModelAndView diffPage(ModelMap m, @PathVariable("title") final String title, @RequestParam(value = "versionL", required = true) final String versionL, @RequestParam(value = "versionR", required = true) final String versionR) throws Exception { // Page p2 = getPageByTitle(title); pageAclService.checkReadable(p2); // Optional<PageContent> versionL_ = getVersion(p2, versionL); checkVersionFound(versionL_, title, p2); Optional<PageContent> versionR_ = getVersion(p2, versionR); checkVersionFound(versionR_, title, p2); // m.put("page", p2); m.put("versionL", versionL_.get()); m.put("versionR", versionR_.get()); // return new ModelAndView("page/diff", m); } @RequestMapping(value = "/recents") public ModelAndView recents(ModelMap m) { return new ModelAndView("recents/list", m); } }