Compare commits

...

5 Commits

11 changed files with 356 additions and 212 deletions

View File

@ -25,13 +25,6 @@
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="test" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>

11
pom.xml
View File

@ -7,7 +7,7 @@
<groupId>com.mousetech.gourmet</groupId>
<artifactId>gourmetj</artifactId>
<version>2.0.4</version>
<version>2.0.37</version>
<packaging>jar</packaging>
<name>GourmetJ</name>
@ -172,6 +172,15 @@
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>

View File

@ -1,7 +1,6 @@
package com.mousetech.gourmetj;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
@ -67,14 +66,6 @@ public class AdminMainBean implements Serializable {
return cookieBean;
}
/**
* @param cookieBean the cookieBean to set.
* @deprecated Not invoked by @Inject
*/
public void setCookieBean(CookieBean cookieBean) {
this.cookieBean = cookieBean;
}
// **
@Inject
private UserSession userSession;
@ -248,6 +239,7 @@ public class AdminMainBean implements Serializable {
this.userSession.setLastEdit(null);
// Construct a blank recipe to be created.
this.userSession.setRecipe(new Recipe());
this.userSession.setDetailTab(0); // title tab
return "detailEdit?faces-redirect=true";
}

View File

@ -124,7 +124,7 @@ public class CookieBean {
// **
public Integer getDisplayListSize() {
if (!cookieMap.containsKey(KEY_DISPLAY_ROWS)) {
cookieMap.put(KEY_DISPLAY_ROWS, "30");
cookieMap.put(KEY_DISPLAY_ROWS, "0");
}
String st = cookieMap.get(KEY_DISPLAY_ROWS);
return Integer.valueOf(String.valueOf(st));

View File

@ -243,7 +243,7 @@ public class RecipeDetailBean implements Serializable {
this.shop = this.getUserSession().getShoppingList()
.contains(recipe);
log.info("Set recipe: " + this.recipe);
log.debug("Set recipe: " + this.recipe);
}
/**
@ -358,8 +358,8 @@ public class RecipeDetailBean implements Serializable {
return "";
}
String s = instructions.replace("\r\n", "<p/>")
.replace("\n\n", "<p/>");
s = s.replace("\n", "<br/>");
.replace("\n\n", "<p/>")
.replace("\n", "<br/>");
return s;
}
@ -643,7 +643,7 @@ public class RecipeDetailBean implements Serializable {
* @see #addIngredientList(String)
*/
public void addIngredient(String ingredientText) {
log.info("Ingredient line: \"" + ingredientText + "\"");
log.debug("Ingredient line: \"" + ingredientText + "\"");
Ingredient ing =
IngredientDigester.digest(ingredientText);
@ -977,7 +977,7 @@ public class RecipeDetailBean implements Serializable {
}
public void ajaxUpdateShopcat(IngredientUI item) {
log.warn("SHOPCAT2 ");
log.debug("SHOPCAT2 ");
updateShopcat(item);
}

View File

@ -1,6 +1,10 @@
package com.mousetech.gourmetj;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
@ -144,6 +148,54 @@ public class UserSession implements Serializable {
return sb.toString();
}
/**
* Display source. If no "source" and there's a URL,
* use that.
*
* @param ltime
* @return
*/
public String formatSource(Recipe r) {
String s = r.getSource();
if ( s != null && ! s.isBlank()) {
return s;
}
s = r.getLink();
return urlToSource(s);
}
/**
* Take a URL and strip it of everything but
* the base domain name (including ".com")
* @param s URL string.
* @return Processed domain name.
* TestedBy: UserSessionTest
*/
String urlToSource(String s) {
if ( s == null || s.isBlank()) {
return ""; // no source, no URL
}
try {
if ( ! s.startsWith("http")) {
s = "http://" + s; // Convert to absolute URI
}
URL u = new URI(s).toURL();
String s1 = u.getHost();
if ( s1.startsWith("www.")) {
s1 = s1.substring("www.".length());
}
if ( s1.endsWith(".com")) {
// mousetech.com
s1 = s1.substring(0, s1.length() - ".com".length());
}
return s1;
} catch (MalformedURLException e) {
return s;
} catch (URISyntaxException e) {
return s;
}
}
/*
* @Deprecated Using TimeConverter.
*/

View File

@ -0,0 +1,163 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://xmlns.jcp.org/jstl"
>
<!-- Overview tab body -->
<p:panelGrid columns="2"
columnClasses="deDescl, deDescr"
>
<f:facet name="header">Description</f:facet>
<p:row>
<p:column styleClass="deDescl">
<p:outputLabel value="Title" />
</p:column>
<p:column styleClass="deDescr" colspan="3">
<p:inputText id="rtitle" size="45"
required="true"
placeholder="A recipe title is required."
value="#{recipeDetailBean.recipe.title}"
>
<p:focus />
<f:ajax execute="rtitle"
render="editorPanel" />
</p:inputText>
</p:column>
</p:row>
<!-- -->
<p:row>
<p:column styleClass="deDescl">
<p:outputLabel value="Category" />
</p:column>
<p:column styleClass="deDescr" colspan="3">
<p:inputText id="rcategory"
label="Category"
value="#{recipeDetailBean.category}"
tip="One or more categories, separated by commas (ex: Entree, Soup)" />
<p:commandButton
value="&lt;- Suggest"
>
<f:ajax execute="rcategory bxCat"
listener="#{recipeDetailBean.ajaxSuggestCategory}"
render="rcategory" />
</p:commandButton>
<p:selectOneMenu id="bxCat"
value="#{recipeDetailBean.catToAdd}"
tip="Recipe category suggestions, based on previous selections"
>
<f:selectItems
value="#{recipeDetailBean.suggestCategory}" />
</p:selectOneMenu>
</p:column>
</p:row>
<!-- -->
<p:row>
<p:column styleClass="deDescl">
<p:outputLabel value="Cuisine" />
</p:column>
<p:column styleClass="deDescr" colspan="3">
<p:autoComplete id="rcuisine"
value="#{recipeDetailBean.recipe.cuisine}"
completeMethod="#{recipeDetailBean.cuisineSuggestions}" />
</p:column>
</p:row>
<p:row>
<p:column styleClass="deDescr" colspan="3">
<p:outputLabel value="Prep Time" />
<p:inputText id="rpreptime" max="10"
value="#{recipeDetailBean.recipe.preptime}"
>
<f:converter
converterId="com.mousetech.gourmetj.utils.TimeConverter" />
</p:inputText>
</p:column>
</p:row>
<!-- -->
<p:row>
<p:column styleClass="deDescl">
<p:outputLabel value="Cooking Time" />
</p:column>
<p:column styleClass="deDescr" colspan="3">
<p:inputText id="rcooktime" max="10"
value="#{recipeDetailBean.recipe.cooktime}"
>
<f:converter
converterId="com.mousetech.gourmetj.utils.TimeConverter" />
</p:inputText>
</p:column>
</p:row>
<p:row>
<p:column styleClass="deDescl">
<p:outputLabel value="Servings" />
</p:column>
<p:column styleClass="deDescr" colspan="3">
<p:inputText id="rserves" max="10"
value="#{recipeDetailBean.recipe.servings}" />
</p:column>
</p:row>
<p:row>
<p:column styleClass="deDescl">
<p:outputLabel value="Rating" />
</p:column>
<p:column styleClass="deDescr" colspan="3">
<p:rating id="rrating" max="10"
value="#{recipeDetailBean.recipe.rating}" />
</p:column>
</p:row>
<p:row>
<p:column styleClass="deDescl">
<p:outputLabel value="Source" />
</p:column>
<p:column styleClass="deDescr" colspan="3">
<p:inputText id="rsource" size="45"
value="#{recipeDetailBean.recipe.source}" />
</p:column>
</p:row>
<p:row>
<p:column styleClass="deDescl">
<p:outputLabel value="URL" />
</p:column>
<p:column styleClass="deDescr" colspan="3">
<p:inputText id="rurl" size="45"
value="#{recipeDetailBean.recipe.link}" />
</p:column>
</p:row>
<p:row>
<p:column styleClass="deDescl" colspan="3">
<p:outputLabel value="Description" />
</p:column>
<p:column styleClass="deDescr" colspan="3">
<p:inputTextarea id="description"
rows="10" cols="45"
value="#{recipeDetailBean.recipe.description}" />
</p:column>
</p:row>
</p:panelGrid>
<p:panelGrid id="ppGrid" columns="2">
<p:panel id="picPanel">
<img id="bigPix"
src="/img/picture/?dt=#{recipeDetailBean.currentTime}" />
</p:panel>
<p:panelGrid id="picButtonPanel" columns="1">
<p:fileUpload id="ctlUpload"
label="Upload Image"
listener="#{recipeDetailBean.ajaxUploadImage}"
global="true" mode="advanced" multiple="false"
update="picPanel" auto="true" sizeLimit="1000000"
allowTypes="/(\.|\/)(gif|jpe?g|png|webp)$/" />
<p:commandButton id="ctlDelImg"
value="Delete Image"
action="#{recipeDetailBean.ajaxDeleteImage}"
update="picPanel" immediate="true" />
</p:panelGrid>
</p:panelGrid>
</ui:composition>

View File

@ -42,6 +42,10 @@
font-weight: bold;
background-color: green;
}
.noBorders .noBorders tr, .noBorders td {
background: none !important;
border: none !important;
}
</style>
<h:messages id="messages" />
<p:panel id="editorPanel"
@ -55,129 +59,8 @@
<p:tab id="overviewTab"
title="Description"
>
<p:panelGrid columns="2"
columnClasses="deDescl, deDescr"
>
<f:facet name="header">Description</f:facet>
<p:outputLabel for="@next"
value="Title"
/>
<p:inputText id="rtitle"
size="45" required="true"
placeholder="A recipe title is required."
value="#{recipeDetailBean.recipe.title}"
>
<p:focus />
<f:ajax execute="rtitle"
render="editorPanel"
/>
</p:inputText>
<p:outputLabel for="@next"
value="Category"
/>
<p:inputText id="rcategory"
label="Category"
value="#{recipeDetailBean.category}"
tip="One or more categories, separated by commas (ex: Entree, Soup)"
/>
<p:commandButton
value="&lt;- Suggest"
>
<f:ajax
execute="rcategory bxCat"
listener="#{recipeDetailBean.ajaxSuggestCategory}"
render="rcategory"
/>
</p:commandButton>
<p:selectOneMenu id="bxCat"
value="#{recipeDetailBean.catToAdd}"
tip="Recipe category suggestions, based on previous selections"
>
<f:selectItems
value="#{recipeDetailBean.suggestCategory}"
/>
</p:selectOneMenu>
<p:outputLabel for="@next"
value="Cuisine"
/>
<p:autoComplete id="rcuisine"
value="#{recipeDetailBean.recipe.cuisine}"
completeMethod="#{recipeDetailBean.cuisineSuggestions}"
/>
<p:outputLabel for="@next"
value="Prep Time"
/>
<p:inputText id="rpreptime"
max="10"
value="#{recipeDetailBean.recipe.preptime}"
>
<f:converter
converterId="com.mousetech.gourmetj.utils.TimeConverter"
/>
</p:inputText>
<p:outputLabel for="@next"
value="Cooking Time"
/>
<p:inputText id="rcooktime"
max="10"
value="#{recipeDetailBean.recipe.cooktime}"
>
<f:converter
converterId="com.mousetech.gourmetj.utils.TimeConverter"
/>
</p:inputText>
<p:outputLabel for="@next"
value="Rating"
/>
<p:rating id="rrating" max="10"
value="#{recipeDetailBean.recipe.rating}"
/>
<p:outputLabel for="@next"
value="Source"
/>
<p:inputText id="rsource"
size="45"
value="#{recipeDetailBean.recipe.source}"
/>
<p:outputLabel for="@next"
value="URL"
/>
<p:inputText id="rurl" size="45"
value="#{recipeDetailBean.recipe.link}"
/>
<p:outputLabel for="@next"
value="Description"
/>
<p:inputTextarea id="description"
rows="10" cols="45"
value="#{recipeDetailBean.recipe.description}"
/>
</p:panelGrid>
<p:panel id="picPanel">
<img id="bigPix"
src="/img/picture/?dt=#{recipeDetailBean.currentTime}"
/>
</p:panel>
<p:panelGrid id="picButtonPanel"
columns="2"
>
<p:fileUpload id="ctlUpload"
label="Upload Image"
listener="#{recipeDetailBean.ajaxUploadImage}"
global="true" mode="advanced"
multiple="false"
update=":messages picPanel"
auto="true"
sizeLimit="1000000"
allowTypes="/(\.|\/)(gif|jpe?g|png|webp)$/"
/>
<p:commandButton id="ctlDelImg"
value="Delete Image"
action="#{recipeDetailBean.ajaxDeleteImage}"
update="picPanel"
immediate="true"
/>
</p:panelGrid>
<ui:include
src="/WEB-INF/layout/panels/editRecipe/overview.xhtml"/>
</p:tab>
<p:tab id="ingredientsTab"
title="Ingredients"

View File

@ -57,7 +57,7 @@
value="#{cookieBean.displayListSize}"
/>
<h:outputLabel for="slistSize"
value=" Recipes in Shopping List"
value=" Recipes in Shopping List "
/>
<p:commandButton id="logout" value="Logout"
action="#{adminMainBean.doLogout}"
@ -98,7 +98,7 @@
/>
</p:column>
<p:column headerText="Source">
<h:outputText value="#{row.source}" />
<h:outputText value="#{userSession.formatSource(row)}" />
</p:column>
<p:column headerText="Prep Time">
<h:outputText value="#{row.preptime}"

View File

@ -35,71 +35,98 @@
/>
</f:facet>
<p:panel id="leftCol" style="width: auto;">
<p:panelGrid columns="2">
<p:panelGrid id="picButtons" columns="2">
<img id="bigpix"
style="width: 132px;"
src="/img/picture/#{recipeDetailBean.recipe.id}"
/>
<p:panelGrid id="pnlButtons"
columns="2" style="width: 220px;"
>
<!-- TODO: ask if we should save -->
<p:commandButton value="Back"
ajax="false"
icon="ui-icon-arrowthick-1-w"
action="home"
immediate="true"
<p:panelGrid>
<p:row>
<p:column style="width: 136px;">
<p:graphicImage id="bigpix"
style="width: 132px;"
value="/img/picture/#{recipeDetailBean.recipe.id}"
/>
<p:commandButton ajax="false"
value="Print"
icon="ui-icon-print"
action="/recipePrint.jsf?faces-redirect=true"
styleClass="ui-button-print"
immediate="true"
/>
<p:commandButton id="ctlShop"
icon="ui-icon-cart"
value="Shop" immediate="true"
styleClass="#{recipeDetailBean.shop ? 'greenButton' : null}"
action="#{recipeDetailBean.doShop}"
update="ctlShop"
/>
<h:outputText value="" />
<p:outputLabel for="@next"
value="Categories:"
/>
<h:outputText label="Category: "
value="#{userSession.formatCategories(recipeDetailBean.recipe)}"
/>
<p:outputLabel for="@next"
value="Cuisine:"
/>
<h:outputText label="Cuisine: "
value="#{recipeDetailBean.recipe.cuisine}"
/>
<p:outputLabel for="@next"
value="Prep Time:"
/>
<h:outputText label="Prep Time: "
value="#{recipeDetailBean.recipe.preptime}"
converter="com.mousetech.gourmetj.utils.TimeConverter"
/>
<p:outputLabel for="@next"
value="Cook Time:"
/>
<h:outputText label="Cook Time: "
value="#{recipeDetailBean.recipe.cooktime}"
converter="com.mousetech.gourmetj.utils.TimeConverter"
/>
<h:outputText value="" />
<p:commandButton
icon="ui-icon-wrench"
value="Edit"
action="#{recipeDetailBean.editDescription}"
/>
</p:panelGrid>
</p:panelGrid>
</p:column>
<p:column style="width: 18em;">
<p:panelGrid id="pnlButtons"
columns="2"
>
<!-- TODO: ask if we should save -->
<p:commandButton value="Home"
ajax="false"
icon="ui-icon-home"
action="home"
immediate="true"
/>
<p:commandButton ajax="false"
value="Print"
icon="ui-icon-print"
action="/recipePrint.jsf?faces-redirect=true"
styleClass="ui-button-print"
immediate="true"
/>
<p:commandButton id="ctlShop"
icon="ui-icon-cart"
value="Shop"
immediate="true"
styleClass="#{recipeDetailBean.shop ? 'greenButton' : null}"
action="#{recipeDetailBean.doShop}"
update="ctlShop"
/>
<p:commandButton
icon="ui-icon-wrench"
value="Edit"
action="#{recipeDetailBean.editDescription}"
/>
<p:outputLabel for="@next"
value="Categories:"
/>
<h:outputText
label="Category: "
value="#{userSession.formatCategories(recipeDetailBean.recipe)}"
/>
<p:outputLabel for="@next"
value="Cuisine:"
/>
<h:outputText
label="Cuisine: "
value="#{recipeDetailBean.recipe.cuisine}"
/>
<p:outputLabel for="@next"
value="Prep Time:"
/>
<h:outputText
label="Prep Time: "
value="#{recipeDetailBean.recipe.preptime}"
converter="com.mousetech.gourmetj.utils.TimeConverter"
/>
<p:outputLabel for="@next"
value="Cook Time:"
/>
<h:outputText
label="Cook Time: "
value="#{recipeDetailBean.recipe.cooktime}"
converter="com.mousetech.gourmetj.utils.TimeConverter"
/>
<p:outputLabel for="@next"
value="Servings:"
/>
<h:outputText
value="#{recipeDetailBean.recipe.servings}"
/>
</p:panelGrid>
</p:column>
<p:column>
<p:panel id="sources" style="width: fit-content;">
<h:outputText
value="#{recipeDetailBean.recipe.source}"
/>
<br />
<h:outputLink
value="#{recipeDetailBean.recipe.link}"
rendered="#{not empty recipeDetailBean.recipe.link}"
>
#{recipeDetailBean.recipe.link}
</h:outputLink>
</p:panel>
</p:column>
</p:row>
</p:panelGrid>
<!-- -->
<p:panel id="pnlInstr">

View File

@ -0,0 +1,25 @@
package com.mousetech.gourmetj;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
class UserSessionTest {
@Test
void testformatSource() {
UserSession us = new UserSession();
assertEquals("mousetech",
us.urlToSource("www.mousetech.com"));
assertEquals("google",
us.urlToSource("google.com"));
assertEquals("foobar",
us.urlToSource("foobar"));
assertEquals("",
us.urlToSource("\t"));
assertEquals("",
us.urlToSource(null));
}
}