package controllers;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
import javax.jcr.query.Row;
import javax.jcr.query.RowIterator;
import models.Recipe;
import models.User;
import org.apache.commons.lang.StringUtils;
import org.jcrom.JcrFile;
import org.jcrom.JcrMappingException;
import play.Logger;
import play.Play;
import play.data.validation.Email;
import play.data.validation.Required;
import play.data.validation.Valid;
import play.libs.MimeTypes;
import play.modules.cream.JCR;
import play.modules.cream.ocm.JcrMapper;
import play.modules.cream.ocm.JcrQueryResult;
import play.modules.cream.ocm.JcrVersionMapper;
import play.mvc.Before;
import play.mvc.Controller;
import play.mvc.With;
@With(Secure.class)
public class Application extends Controller {
private static final String RECIPES_PATH = JcrMapper.getDefaultPath(Recipe.class);
// If you need direct access to jcrSession
// @Inject
// static Session jcrSession;
static Integer pageSize = Integer.parseInt(Play.configuration.getProperty("tables.pageSize", "5"));
public static void add(Recipe recipe) {
recipe = (recipe == null) ? new Recipe() : recipe;
render(recipe);
}
public static void authenticate(@Required @Email String email, @Required String password) {
if (validation.hasErrors()) {
validation.keep();
params.flash();
flash.error("Please correct these errors !");
login();
}
User user = User.findByEmail(email).first();
if (user == null || !user.checkPassword(password)) {
flash.error("Bad email or bad password");
flash.put("email", email);
login();
}
Secure.connect(user);
flash.success("Welcome back %s !", user.name);
index(1);
}
@Secure.Authenticated
public static void create(@Valid Recipe recipe, File image) {
if (validation.hasErrors()) {
validation.keep();
flash.error("Please correct these errors !");
add(recipe);
}
if (image != null) {
addImageToRecipe(recipe, image);
}
recipe.name = recipe.title;
// if you want to create the recipe in another path set
// recipe.path = "/mypath";
recipe.author = Secure.connectedUser();
recipe.create();
index(1);
}
@Secure.Authenticated
public static void delete(String id) {
Recipe recipe = getRecipeAndCheck(id);
recipe.delete();
flash.success("Deleted %s", recipe.title);
index(1);
}
public static void deleteVersion(String id, String versionName) {
try {
JcrVersionMapper.removeVersionByUUID(id, versionName);
flash.success("Version %s deleted", versionName);
} catch (JcrMappingException e) {
flash.error(e.getMessage());
}
history(id);
}
public static void edit(String id) {
Recipe recipe = getRecipeAndCheck(id);
render(recipe);
}
public static void getImage(String id) {
Recipe recipe = getRecipe(id);
response.setContentTypeIfNotSet(recipe.image.getMimeType());
renderBinary(recipe.image.getDataProvider().getInputStream());
}
public static void history(String id) {
Recipe recipe = getRecipe(id);
render(recipe);
}
public static void index(Integer page) {
page = (page != null && page > 0) ? page : 1;
JcrQueryResult result = Recipe.findBy("order by [jcr:created] desc");
long nbRecipes = result.count();
List<Recipe> recipes = result.fetch(page, pageSize);
render(nbRecipes, recipes, page);
}
public static void login() {
render();
}
@Secure.Authenticated
public static void logout() {
flash.success("You've been logged out");
session.clear();
index(1);
}
public static void restore(String id, String versionName) {
JcrVersionMapper.restoreVersionByUUID(id, versionName);
flash.success("Version %s restored", versionName);
show(id);
}
public static void search(String query) {
// Naive sanitize
query = query.replaceAll("[^\\w s]", "");
List<Recipe> recipes = new ArrayList<Recipe>();
if (StringUtils.isNotBlank(query)) {
// XXX see
// http://jackrabbit.510166.n4.nabble.com/Use-of-excerpt-with-SQL2-td3249018.html
// waiting for excerpt support with SQL-2
try {
QueryManager qm = JCR.getQueryManager();
@SuppressWarnings("deprecation")
Query q = qm.createQuery("select excerpt(.) from nt:unstructured where jcr:path like '" + RECIPES_PATH
+ "/%' and contains(., '" + query + "') order by jcr:score desc", Query.SQL);
QueryResult result = q.execute();
for (RowIterator it = result.getRows(); it.hasNext();) {
Row r = it.nextRow();
Value excerpt = r.getValue("rep:excerpt(.)");
Recipe recipe = JcrMapper.fromNode(Recipe.class, r.getNode());
recipe.description = excerpt.getString().replaceAll("<.*?>", "");
recipes.add(recipe);
}
} catch (RepositoryException e) {
Logger.error(e.getMessage(), e);
}
}
render(recipes, query);
}
public static void show(String id) {
Recipe recipe = getRecipe(id);
boolean editable = Secure.checkRecipeAccess(recipe);
render(recipe, editable);
}
public static void showVersion(String id, String vid) {
Recipe recipe = getRecipe(id);
Recipe recipeVersion = getRecipe(vid);
boolean editable = Secure.checkRecipeAccess(recipe);
render(recipe, recipeVersion, editable);
}
public static void update(@Valid Recipe recipe, File image) {
Secure.checkRecipeAccess(recipe);
String uuid = recipe.uuid;
if (validation.hasErrors()) {
validation.keep();
flash.error("Please correct these errors !");
edit(uuid);
}
int depth = -1;
if (image == null) {
depth = 0;
} else {
addImageToRecipe(recipe, image);
}
recipe.merge("*", depth);
show(uuid);
}
@Before
static void globals() {
renderArgs.put("pageSize", pageSize);
}
private static void addImageToRecipe(Recipe recipe, File image) {
recipe.image = JcrFile.fromFile("picture", image, MimeTypes.getContentType(image.getName()));
}
private static Recipe getRecipe(String id) {
Recipe recipe = Recipe.findById(id);
notFoundIfNull(recipe);
return recipe;
}
private static Recipe getRecipeAndCheck(String id) {
Recipe recipe = getRecipe(id);
Secure.checkRecipeAccess(recipe);
return recipe;
}
}