Permalink
Browse files

More Lift 2.2 modifications and fixes

Closes #10
Closes #9

Added designer-friendly template for add entry
  • Loading branch information...
1 parent 091f1ba commit 0302e903679f666224da4914e6e01f6386872a81 @dchenbecker dchenbecker committed Jan 16, 2011
View
@@ -12,7 +12,7 @@
-->
<properties>
<scala.version>2.8.1</scala.version>
- <lift.version>2.2-RC6</lift.version>
+ <lift.version>2.2</lift.version>
</properties>
<pluginRepositories>
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
-<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
- <appender name="appender" class="org.apache.log4j.ConsoleAppender">
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="%r [%t] %-5p %c %x - %m%n" />
- </layout>
- </appender>
- <root>
- <priority value ="DEBUG"/>
- <appender-ref ref="appender"/>
- </root>
-</log4j:configuration>
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<configuration scan="true">
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%d [%t] %-5p %logger{25} - %m%n</pattern>
+ </encoder>
+ </appender>
+ <root level="DEBUG">
+ <appender-ref ref="STDOUT"/>
+ </root>
+</configuration>
@@ -6,6 +6,7 @@ import scala.xml.{NodeSeq,Text}
import net.liftweb.common.{Box,Empty,Full,Logger}
import net.liftweb.http.{FileParamHolder,S,SHtml,StatefulSnippet}
import org.slf4j.LoggerFactory
+import java.text.ParseException
// Import "bind", as well as the implicits that make bind easy
import net.liftweb.util.Helpers._
@@ -33,70 +34,90 @@ class AddEntry extends StatefulSnippet with Logger {
case Full(user) if user.editable.size > 0 => {
def doTagsAndSubmit(t: String) {
tags = t
- if (tags.trim.length == 0) {
- error("Cannot add an entry without tags")
- S.error("We're going to need at least one tag.")
+
+ // Pre-validate the unparsed values
+ val requiredFields = List((date, "a date"), (desc, "a description"), (value, "a value"), (tags, "tags"))
+
+ val missing = requiredFields.flatMap { case (field,label) =>
+ if (field.trim.length == 0) {
+ Some(label)
+ } else {
+ None
+ }
+ }
+
+ if (! missing.isEmpty) {
+ missing.foreach { label =>
+ error("Entry add attempted without " + label)
+ S.error("You must provide " + label)
+ }
} else {
- /* Get the date correctly, add the datepicker: comes in as yyyy/mm/dd */
- val entryDate = Util.slashDate.parse(date)
+ try {
+ /* Get the date correctly, add the datepicker: comes in as yyyy/mm/dd */
+ val entryDate = Util.slashDate.parse(date)
- val amount = BigDecimal(value)
+ val amount = BigDecimal(value)
- // Rework to not throw exceptions
- val currentAccount = Account.find(account).open_!
+ // Rework to not throw exceptions
+ val currentAccount = Account.find(account).open_!
- // We need to determine the last serial number and balance for the date in question
- val (entrySerial,entryBalance) = Expense.getLastExpenseData(currentAccount, entryDate)
+ // We need to determine the last serial number and balance for the date in question
+ val (entrySerial,entryBalance) = Expense.getLastExpenseData(currentAccount, entryDate)
- val e =
- Expense.create.account(account).dateOf(entryDate).serialNumber(entrySerial + 1)
- .description(desc).amount(BigDecimal(value)).tags(tags)
- .currentBalance(entryBalance + amount)
+ val e =
+ Expense.create.account(account).dateOf(entryDate).serialNumber(entrySerial + 1)
+ .description(desc).amount(BigDecimal(value)).tags(tags)
+ .currentBalance(entryBalance + amount)
- // Add the optional receipt if it's the correct type
- val receiptOk = fileHolder match {
- case Full(FileParamHolder(_, null, _, _)) => true
- case Full(FileParamHolder(_, mime, _, data))
- if mime.startsWith("image/") => {
- e.receipt(data).receiptMime(mime)
- true
+ // Add the optional receipt if it's the correct type
+ val receiptOk = fileHolder match {
+ case Full(FileParamHolder(_, null, _, _)) => true
+ case Full(FileParamHolder(_, mime, _, data))
+ if mime.startsWith("image/") => {
+ e.receipt(data).receiptMime(mime)
+ true
+ }
+ // If someone sends nothing...
+ case Full(FileParamHolder(_, _, "", _)) => true
+ case Full(something) => {
+ error("Received invalid file attachment: " + something)
+ S.error("Invalid receipt attachment")
+ false
+ }
+ case _ => true
}
- // If someone sends nothing...
- case Full(FileParamHolder(_, _, "", _)) => true
- case Full(something) => {
- error("Received invalid file attachment: " + something)
- S.error("Invalid receipt attachment")
- false
- }
- case _ => true
- }
-
- (e.validate,receiptOk) match {
- case (Nil,true) => {
- Expense.updateEntries(entrySerial + 1, amount)
- e.save
- val acct = Account.find(account).open_!
- val newBalance = acct.balance.is + e.amount.is
- acct.balance(newBalance).save
- S.notice("Entry added!")
- this.unregisterThisSnippet() // dpp: remove the statefullness of this snippet
- }
- case (x,_) => {
- error(x)
- S.error(x)
+
+ (e.validate,receiptOk) match {
+ case (Nil,true) => {
+ Expense.updateEntries(entrySerial + 1, amount)
+ e.save
+ val acct = Account.find(account).open_!
+ val newBalance = acct.balance.is + e.amount.is
+ acct.balance(newBalance).save
+ S.notice("Entry added!")
+ this.unregisterThisSnippet() // dpp: remove the statefullness of this snippet
+ S.redirectTo("/")
+ }
+ case (x,_) => {
+ error(x)
+ S.error(x)
+ }
}
+ } catch {
+ case pe : ParseException => error(pe); S.error("Invalid date: " + date)
+ case nfe : NumberFormatException => error(nfe); S.error("Invalid value: " + value)
}
}
}
bind("e", in,
- "account" -> SHtml.select(user.editable.map(acct => (acct.id.toString, acct.name.toString)), Empty, id => account = id.toLong),
+ "account" -%> SHtml.select(user.editable.map(acct => (acct.id.toString, acct.name.toString)), Empty, id => account = id.toLong),
// Note that we use "-%>" so that the id and maxlength attrs on the template are preserved
- "dateOf" -%> SHtml.text("", date = _) % ("size" -> "10"),
- "desc" -> SHtml.text("", desc = _),
- "value" -> SHtml.text("", value = _),
- "receipt" -> SHtml.fileUpload(fph => fileHolder = Full(fph)),
- "tags" -> SHtml.text(tags, doTagsAndSubmit))
+ "dateOf" -%> SHtml.text(date, date = _),
+ "desc" -%> SHtml.text(desc, desc = _),
+ "value" -%> SHtml.text(value, value = _),
+ "receipt" -%> SHtml.fileUpload(fph => fileHolder = Full(fph)),
+ "tags" -%> SHtml.text(tags, doTagsAndSubmit))
}
case _ => Text("")
}
@@ -5,10 +5,9 @@ import scala.xml.{NodeSeq,Text}
import model.User
import net.liftweb.common.{Logger, Full}
-import net.liftweb.http.DispatchSnippet
// Import Helper's implicits for binding
-import net.liftweb.util.Helpers._
+import net.liftweb.util.BindHelpers._
/**
* This is the home page snippet. Unlike the Accounts and AddEntry snippet classes,
@@ -18,15 +17,21 @@ import net.liftweb.util.Helpers._
class HomePage extends Logger {
def render (xhtml : NodeSeq) : NodeSeq = User.currentUser match {
case Full(user) => {
- val entries : NodeSeq = user.allAccounts match {
- case Nil => Text("You have no accounts set up") // TODO: Add link to create one...
- case accounts => accounts.flatMap({account =>
- bind("acct", chooseTemplate("account", "entry", xhtml),
- "name" -> <a href={"/account/" + account.name.is}>{account.name.is}</a>,
- "balance" -> Text(account.balance.toString))
- })
- }
- bind("account", xhtml, "entry" -> entries)
+ user.allAccounts match {
+ case Nil => Text("You have no accounts set up, ") ++
+ <lift:Menu.item name="Add Account">please add one</lift:Menu.item>
+ case accounts =>
+ ("#summary" #> {
+ "li" #> accounts.map { account =>
+ "a [href]" #> ("/account/" + account.name.is) &
+ "a *" #> account.name &
+ "a [class+]" #> "foo" &
+ "#balance" #> account.balance
+ }
+ } &
+ "#total" #> accounts.map(_.balance.is).sum.toString
+ ).apply(xhtml) // apply the CSS binding to the input XHTML
+ }
}
case _ => <lift:embed what="welcome_msg" />
}
@@ -35,40 +35,43 @@
}
</style>
</head>
- <lift:HomePage>
- <div class="column span-24 bordered">
- <h2>Summary of accounts:</h2>
- <account:entry>
- <acct:name /> : <acct:balance /> <br/>
- </account:entry>
+ <div class="lift:HomePage">
+ <div class="column span-24 bordered">
+ <h2>Summary of accounts:</h2>
+ <ul id="summary">
+ <li><a href="#">Account</a> : <span id="balance">$0</span></li>
+ </ul>
+ <p>Total: <span id="total">$0</span></p>
+ </div>
</div>
-
- <hr />
- </lift:HomePage>
+
+ <hr />
<div class="column span-24">
<lift:AddEntry.addentry form="POST" multipart="true" >
<div class="column span-24"><h3>Entry Form</h3>
- <div id="entryform">
+ <div id="entryform" style="height: 120px">
<table>
<tr>
<td>Account</td>
<td>Date</td>
<td>Description</td>
<td>Value</td>
- <td>Receipt Image</td>
- <td>Tags</td>
+ <td>Tags (comma separated)</td>
<td></td>
</tr>
<tr>
<td><e:account /></td>
- <td><e:dateOf id="entrydate" maxlength="10"/></td>
+ <td><e:dateOf id="entrydate" maxlength="10" size="8"/></td>
<td><e:desc /></td>
- <td><e:value /></td>
- <td><e:receipt /></td>
- <td><e:tags /></td>
+ <td><e:value size="6"/></td>
+ <td><e:tags size="15" /></td>
<td><button>Add Expense</button></td>
</tr>
+ <tr>
+ <td>Receipt Image</td>
+ <td colspan="2"><e:receipt /></td>
+ </tr>
</table>
</div>
</div>
@@ -21,7 +21,7 @@
</div>
<br />
- <h3><a href="/editAcct">Do you need to add an Account?</a></h3>
+ <h3><lift:Menu.item name="Add Account"/></h3>
</div>
</lift:surround>
@@ -24,7 +24,11 @@ color: white;
margin-bottom: 15px;
height: 80px;
text-size: 160%;
+}
+#entryform th {
+ color: white;
+ background: #60a8c0;
}
#formBox {
@@ -54,7 +54,7 @@
<hr />
<div class="column span-24 last" style="text-align: center">
- Copyright © 2009, 2010 - Marius Danciu, Derek Chen-Becker and Tyler Weir
+ Copyright © 2009-2011 - Marius Danciu, Derek Chen-Becker and Tyler Weir
</div>
<script>
@@ -23,7 +23,7 @@
<div>
<h3>Filters:</h3>
- <table>
+ <table id="entryform">
<tr>
<th>Start Date</th>
<td><acct:startDate /></td>

0 comments on commit 0302e90

Please sign in to comment.