Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Permalink Generation and customization for content #294

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 126 additions & 1 deletion src/main/java/org/jbake/app/Crawler.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import static java.io.File.separator;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
Expand All @@ -20,6 +21,9 @@
import java.util.Set;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;

import com.orientechnologies.orient.core.record.impl.ODocument;

Expand Down Expand Up @@ -56,6 +60,7 @@ public static interface Status {
static final String ROOTPATH = "rootpath";
static final String ID = "id";
static final String NO_EXTENSION_URI = "noExtensionUri";
static final String PERMALINK = "permalink";

}
private static final Logger LOGGER = LoggerFactory.getLogger(Crawler.class);
Expand Down Expand Up @@ -178,9 +183,12 @@ private void crawlSourceFile(final File sourceFile, final String sha1, final Str
}
}

if (config.getBoolean(Keys.URI_NO_EXTENSION)) {
if (config.getBoolean(Keys.URI_NO_EXTENSION)) {
fileContents.put(Attributes.NO_EXTENSION_URI, uri.replace("/index.html", "/"));
}

String permalink = buildPermalink(fileContents);
fileContents.put(Attributes.PERMALINK, permalink);

ODocument doc = new ODocument(documentType);
doc.fields(fileContents);
Expand All @@ -191,6 +199,123 @@ private void crawlSourceFile(final File sourceFile, final String sha1, final Str
LOGGER.warn("{} has an invalid header, it has been ignored!", sourceFile);
}
}

/**
* This function generates permalinks if they are enabled in configuration.
*
* Default pattern is /:filepath
*
* Conditions -
* 1. String ending with ':' is treated as static strings. For example, permalink = /:blogdata:/:filepath, will generate all urls as /blogdata/{actual file path}
* 2. :filepath is reserved to add actual source file path (relative to content root)
* 3. :filename is reserved to add name of source file.
* 4. If the keyword values is array then all values of array are used for generation. For example, if /:tags is used and post has two tags tagA, tagB then url would be /tagA/tagB
* 5. :YEAR, :MONTH, :DAY are reserved to pull related part of content published date.
*
* If uri.noExtension is enabled then permalink generation will use it to generate extension less urls.
*
* on front end, permalinks can be accessed as {content.permalink}
*
* @param fileContents
* @author Manik Magar
* @return
*/
private String buildPermalink(Map<String, Object> fileContents){
String permalink = "";

String separator = File.separator;
String permalinkPattern = config.getString(Attributes.PERMALINK,"/:filepath");
if(config.containsKey(Attributes.PERMALINK +"."+ fileContents.get(Attributes.TYPE))){
permalinkPattern = config.getString(Attributes.PERMALINK +"."+ fileContents.get(Attributes.TYPE));
}
if (permalinkPattern != null && !permalinkPattern.trim().isEmpty()) {

String pattern = permalinkPattern;
if(pattern.startsWith(":")) pattern = separator+pattern;
String[] parts = pattern.split("/:");
List<String> pLink = new ArrayList<String>();


//Check if permalink is specified in the content, Use it as final link
if(fileContents.containsKey(Attributes.PERMALINK) && !StringUtils.isBlank(fileContents.get(Attributes.PERMALINK).toString())){
pLink.add(fileContents.get(Attributes.PERMALINK).toString());
} else {
for (String part : parts){
part = part.trim().replace("/", "");
if (part.endsWith(":")){
pLink.add(part.replace(":", ""));
} else if(part.equalsIgnoreCase("filepath")) {
String path = FileUtil.asPath(fileContents.get(Attributes.FILE).toString()).replace(FileUtil.asPath( contentPath), "");
path = FilenameUtils.removeExtension(path);
// strip off leading / to enable generating non-root based sites
if (path.startsWith("/")) {
path = path.substring(1, path.length());
}
pLink.add(path);
} else if(part.equalsIgnoreCase("filename")) {
String sourcePath = (String) fileContents.get(Attributes.SOURCE_URI);
String fileName = FilenameUtils.getBaseName(sourcePath);
pLink.add(fileName);
} else if(fileContents.containsKey(part)){
Object value = fileContents.get(part);
if (value instanceof String){
pLink.add(value.toString());
} else if (value.getClass().equals(String[].class)){
pLink.addAll(Arrays.asList((String[])value));
}
} else if (Arrays.asList("YEAR","MONTH","DAY").contains(part.toUpperCase())) {
Date publishedDate = (Date) fileContents.get("date");
if(publishedDate != null){
String dateValue = null;
if(part.equalsIgnoreCase("YEAR")){
dateValue = DateFormatUtils.format(publishedDate, "yyyy");
}
if(part.equalsIgnoreCase("MONTH")){
dateValue = DateFormatUtils.format(publishedDate, "MM");
}
if(part.equalsIgnoreCase("DAY")){
dateValue = DateFormatUtils.format(publishedDate, "dd");
}
pLink.add(dateValue);
}
}
}
}

permalink = StringUtils.join(pLink, separator);
permalink = sanitize(permalink).concat(separator);
String uri = permalink;
boolean noExtensionUri = config.getBoolean(Keys.URI_NO_EXTENSION);
if (noExtensionUri) {
uri = uri + "index.html";
} else {
permalink = permalink.substring(0, permalink.length() -1 );
permalink = permalink + config.getString(Keys.OUTPUT_EXTENSION);
uri = permalink;
}
if(uri.startsWith("/")){
uri = uri.substring(1);
}
fileContents.put(Attributes.URI, uri);

//Calculate the root path based on the permalink
File permaFile = new File(contentPath,uri);
String rootPath = getPathToRoot(permaFile);
fileContents.put(Attributes.ROOTPATH,rootPath);
}


return permalink;
}

/**
* Replace the spaces with hyphens
* @return
*/
private String sanitize(String input){
return input.replace(" ", "-");
}


public String getPathToRoot(File sourceFile) {
File rootPath = new File(contentPath);
Expand Down
4 changes: 3 additions & 1 deletion src/main/resources/default.properties
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,6 @@ db.path=cache
# enable extension-less URI option?
uri.noExtension=false
# Set to a prefix path (starting with a slash) for which to generate extension-less URI's (i.e. a folder with index.html in)
uri.noExtension.prefix=
uri.noExtension.prefix=
# set the default permalink to source filepath.
permalink=/:filepath
141 changes: 134 additions & 7 deletions src/test/java/org/jbake/app/CrawlerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,17 @@
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery;

import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.ConfigurationException;
import org.jbake.app.ConfigUtil.Keys;

import java.util.HashMap;
import java.util.Map;
import org.jbake.app.ConfigUtil.Keys;

import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.MapConfiguration;
import org.apache.commons.io.FilenameUtils;
import org.hamcrest.BaseMatcher;
Expand Down Expand Up @@ -134,4 +129,136 @@ public static RegexMatcher matches(String regex){
return new RegexMatcher(regex);
}
}


private Map<String,Object> getPermalinkPost(String permalinkPattern){
config.setProperty("permalink", permalinkPattern);
Crawler crawler = new Crawler(db, sourceFolder, config);
crawler.crawl(new File(sourceFolder.getPath() + File.separator + config.getString(Keys.CONTENT_FOLDER)));

List<ODocument> results = db.getPublishedPostsByTag("PermalinkTest");

assertThat(results.size()).isEqualTo(1);

DocumentList list = DocumentList.wrap(results.iterator());
Map<String,Object> content = list.getFirst();
return content;
}

@Test
public void testPermalinkFilePath(){

Map<String,Object> content = getPermalinkPost("/:filepath");

assertThat(content.get("uri")).isEqualTo("blog/2013/second-post.html");
assertThat(content.get("uri")).isEqualTo(content.get("permalink"));
assertThat(content)
.containsKey(Crawler.Attributes.ROOTPATH)
.containsValue("../../");

}

@Test
public void testPermalinkFilePathWithStatic(){

Map<String,Object> content = getPermalinkPost("/:data:/:filepath");

assertThat(content.get("uri")).isEqualTo("data/blog/2013/second-post.html");
assertThat(content.get("uri")).isEqualTo(content.get("permalink"));
assertThat(content)
.containsKey(Crawler.Attributes.ROOTPATH)
.containsValue("../../../");
}

@Test
public void testPermalinkFilename(){

Map<String,Object> content = getPermalinkPost("/:blog:/:filename");

assertThat(content.get("uri")).isEqualTo("blog/second-post.html");
assertThat(content.get("uri")).isEqualTo(content.get("permalink"));
assertThat(content)
.containsKey(Crawler.Attributes.ROOTPATH)
.containsValue("../");
}

@Test
public void testPermalinkWithDate(){

Map<String,Object> content = getPermalinkPost("/:blog:/:YEAR/:MONTH/:DAY/:filename");

assertThat(content.get("uri")).isEqualTo("blog/2013/02/28/second-post.html");
assertThat(content.get("uri")).isEqualTo(content.get("permalink"));
assertThat(content)
.containsKey(Crawler.Attributes.ROOTPATH)
.containsValue("../../../../");
}

@Test
public void testPermalinkWithTagAndTitle(){

Map<String,Object> content = getPermalinkPost("/:data:/:tags/:title");

assertThat(content.get("uri")).isEqualTo("data/blog/PermalinkTest/Second-Post.html");
assertThat(content.get("uri")).isEqualTo(content.get("permalink"));
assertThat(content)
.containsKey(Crawler.Attributes.ROOTPATH)
.containsValue("../../../");
}


@Test
public void testPermalinkWithTagAndTitleWithNoExtension(){
config.setProperty("uri.noExtension", true);
Map<String,Object> content = getPermalinkPost("/:data:/:tags/:title");

assertThat(content.get("uri")).isEqualTo("data/blog/PermalinkTest/Second-Post/index.html");
assertThat(content.get("permalink")).isEqualTo("data/blog/PermalinkTest/Second-Post/");
assertThat(content)
.containsKey(Crawler.Attributes.ROOTPATH)
.containsValue("../../../../");
}

@Test
public void testPermalinkWithTypePermalink(){
config.setProperty("permalink", "/:filepath");
config.setProperty("permalink.post", "/:blog:/:filename");
Map<String,Object> content = getPermalinkPost("/:filepath");

assertThat(content.get("uri")).isEqualTo("blog/second-post.html");
assertThat(content.get("uri")).isEqualTo(content.get("permalink"));
assertThat(content)
.containsKey(Crawler.Attributes.ROOTPATH)
.containsValue("../");
}

@Test
public void testPermalinkWithMultipleTypePermalink(){
config.setProperty("permalink", "/:filepath");
config.setProperty("permalink.post", "/:blog:/:filename");
config.setProperty("permalink.page", "/:pages:/:filename");
Crawler crawler = new Crawler(db, sourceFolder, config);
crawler.crawl(new File(sourceFolder.getPath() + File.separator + config.getString(Keys.CONTENT_FOLDER)));

List<ODocument> results = db.getPublishedPostsByTag("PermalinkTest");

assertThat(results.size()).isEqualTo(1);

DocumentList list = DocumentList.wrap(results.iterator());
Map<String,Object> content = list.getFirst();

//Verify that post has used permalink.post pattern.
assertThat(content.get("uri")).isEqualTo("blog/second-post.html");
assertThat(content.get("uri")).isEqualTo(content.get("permalink"));

List<ODocument> pageResults = db.getPublishedPages();

DocumentList pages = DocumentList.wrap(pageResults.iterator());
//Verify that page has used permalink.page pattern.
Map<String,Object> page = pages.getFirst();
String url = "pages/"+FilenameUtils.getBaseName((String) page.get("file")) + ".html";
assertThat(page.get("uri")).isEqualTo(url);
assertThat(page.get("uri")).isEqualTo(page.get("permalink"));

}
}
2 changes: 1 addition & 1 deletion src/test/resources/content/blog/2013/second-post.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
title=Second Post
date=2013-02-28
type=post
tags=blog
tags=blog,PermalinkTest
status=published
og={"description": "Something"}
~~~~~~
Expand Down