diff --git a/runtime/twodue/etc/.cvsignore b/runtime/twodue/etc/.cvsignore index d887182c..2ba40480 100644 --- a/runtime/twodue/etc/.cvsignore +++ b/runtime/twodue/etc/.cvsignore @@ -1 +1,2 @@ repository.properties +user.properties diff --git a/runtime/twodue/etc/messages.properties b/runtime/twodue/etc/messages.properties index 6c2c2360..0eea413d 100644 --- a/runtime/twodue/etc/messages.properties +++ b/runtime/twodue/etc/messages.properties @@ -1,6 +1,6 @@ # -*- mode: makefile -*- # -# $Id: messages.properties,v 1.4 2003/01/23 21:22:56 mdb Exp $ +# $Id: messages.properties,v 1.5 2003/11/15 22:55:32 mdb Exp $ # # Translation messages for Two Due application @@ -20,7 +20,9 @@ header.title={0} # # app_footer.wm -app_footer.summary_link=Task Summary +app_footer.summary_link=Task status +app_footer.tasks_link=By priority +app_footer.bycategory_link=By category app_footer.account_link=Login/out # diff --git a/runtime/twodue/etc/user.properties.dist b/runtime/twodue/etc/user.properties.dist new file mode 100644 index 00000000..3ae65a2c --- /dev/null +++ b/runtime/twodue/etc/user.properties.dist @@ -0,0 +1,15 @@ +# +# $Id: user.properties.dist,v 1.1 2003/11/15 22:55:32 mdb Exp $ +# +# Configuration parameters for the Two Due web appication + +# +# These are standard configurations that you probably don't want to change + +login_url = /register/login.wm?from=%R +access_denied_url = access_denied.wm + +# +# The name of the auth cookie + +auth_cookie.name = id_ diff --git a/runtime/twodue/etc/web.xml b/runtime/twodue/etc/web.xml index 7de32772..f6308d51 100644 --- a/runtime/twodue/etc/web.xml +++ b/runtime/twodue/etc/web.xml @@ -26,7 +26,7 @@ site_jar_path - /usr/share/java/webapps/site-data + /export/threerings/webapps/site-data site_messages_path diff --git a/runtime/twodue/src/java/com/samskivert/twodue/TwoDueApp.java b/runtime/twodue/src/java/com/samskivert/twodue/TwoDueApp.java index 4b92322e..d3a16027 100644 --- a/runtime/twodue/src/java/com/samskivert/twodue/TwoDueApp.java +++ b/runtime/twodue/src/java/com/samskivert/twodue/TwoDueApp.java @@ -1,5 +1,5 @@ // -// $Id: TwoDueApp.java,v 1.1 2002/11/08 09:14:21 mdb Exp $ +// $Id: TwoDueApp.java,v 1.2 2003/11/15 22:55:32 mdb Exp $ package com.samskivert.twodue; @@ -14,6 +14,7 @@ import com.samskivert.jdbc.StaticConnectionProvider; import com.samskivert.servlet.JDBCTableSiteIdentifier; import com.samskivert.servlet.SiteIdentifier; import com.samskivert.servlet.user.UserManager; +import com.samskivert.util.ConfigUtil; import com.samskivert.util.ServiceUnavailableException; import com.samskivert.velocity.Application; @@ -51,9 +52,8 @@ public class TwoDueApp extends Application // create a static connection provider _conprov = new StaticConnectionProvider(CONN_CONFIG); - // initialize the user manager - Properties props = new Properties(); - props.put("login_url", "/register/login.wm?from=%R"); + // load up our configuration properties + Properties props = ConfigUtil.loadProperties("user.properties"); _usermgr = new UserManager(props, _conprov); // initialize the task repository diff --git a/runtime/twodue/src/java/com/samskivert/twodue/logic/bycategory.java b/runtime/twodue/src/java/com/samskivert/twodue/logic/bycategory.java new file mode 100644 index 00000000..0043acf7 --- /dev/null +++ b/runtime/twodue/src/java/com/samskivert/twodue/logic/bycategory.java @@ -0,0 +1,171 @@ +// +// $Id: bycategory.java,v 1.1 2003/11/15 22:55:32 mdb Exp $ + +package com.samskivert.twodue.logic; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import javax.servlet.http.HttpServletRequest; + +import com.samskivert.util.StringUtil; + +import com.samskivert.servlet.RedirectException; +import com.samskivert.servlet.user.User; +import com.samskivert.servlet.util.ParameterUtil; +import com.samskivert.velocity.InvocationContext; + +import com.samskivert.twodue.Log; +import com.samskivert.twodue.TwoDueApp; +import com.samskivert.twodue.data.Task; + +/** + * Displays a summary of unclaimed tasks by category. + */ +public class bycategory extends UserLogic +{ + public void invoke (InvocationContext ctx, TwoDueApp app, User user) + throws Exception + { + HttpServletRequest req = ctx.getRequest(); + + // display any message we've been asked to display + String msg = ParameterUtil.getParameter(req, "message", true); + if (!StringUtil.blank(msg)) { + ctx.put("error", msg); + } + + // we use this to determine whether to show "complete" buttons for + // tasks + ctx.put("username", user.username); + + ArrayList tasks = null; + String query = ParameterUtil.getParameter(req, "query", false); + if (StringUtil.blank(query)) { + tasks = app.getRepository().loadTasks(); + } else { + ctx.put("query", query); + tasks = app.getRepository().findTasks(query); + } + + // sort the tasks by priority, then complexity + Collections.sort(tasks, OPEN_PARATOR); + + CatList[] xtasks = categorize(tasks, new Categorizer() { + public String category (Task task) { + return task.category; + } + }); + ctx.put("xtasks", xtasks); + ctx.put("xcats", new CategoryTool()); + + // figure out where to start the second column + int total = 0, current = 0; + for (int ii = 0; ii < xtasks.length; ii++) { + total += xtasks[ii].tasks.size(); + } + for (int ii = 0; ii < xtasks.length; ii++) { + current += xtasks[ii].tasks.size(); + if (current >= total/2) { + ctx.put("break", ii); + break; + } + } + + if (!StringUtil.blank(query) && xtasks.length == 0) { + ctx.put("error", "index.error.no_matching_tasks"); + } + } + + protected static class CatList + implements Comparable + { + public String name; + public ArrayList tasks; + public int compareTo (Object other) + { + return name.compareTo(((CatList)other).name); + } + } + + protected static interface Categorizer + { + public String category (Task task); + } + + protected CatList[] categorize (ArrayList tasks, Categorizer catter) + { + if (tasks == null) { + return new CatList[0]; + } + + ArrayList cats = new ArrayList(); + HashMap cmap = new HashMap(); + int tcount = tasks.size(); + for (int ii = 0; ii < tcount; ii++) { + Task task = (Task)tasks.get(ii); + String category = catter.category(task); + CatList clist = (CatList)cmap.get(category); + if (clist == null) { + clist = new CatList(); + clist.name = category; + clist.tasks = new ArrayList(); + cats.add(clist); + cmap.put(category, clist); + } + clist.tasks.add(task); + } + + CatList[] ctasks = new CatList[cats.size()]; + cats.toArray(ctasks); + + return ctasks; + } + + protected static final Comparator OPEN_PARATOR = new Comparator() { + public int compare (Object o1, Object o2) { + Task t1 = (Task)o1, t2 = (Task)o2; + // sort first by category, then reverse priority, then by complexity + if (t1.category.equals(t2.category)) { + if (t1.priority == t2.priority) { + return t1.getComplexityValue() - t2.getComplexityValue(); + } else { + return t2.priority - t1.priority; + } + } else { + return t1.category.compareTo(t2.category); + } + } + }; + + protected static final Comparator OWNED_PARATOR = new Comparator() { + public int compare (Object o1, Object o2) { + Task t1 = (Task)o1, t2 = (Task)o2; + // sort by complexity + return t1.getComplexityValue() - t2.getComplexityValue(); + } + }; + + // used to easy category generation in UI + public static class CategoryTool + { + public boolean checkCategory (String category) + { + if (category.equals(_category)) { + return false; + } else { + _category = category; + return true; + } + } + + public void clear () + { + _category = null; + } + + protected String _category; + } +} diff --git a/runtime/twodue/src/java/com/samskivert/twodue/logic/index.java b/runtime/twodue/src/java/com/samskivert/twodue/logic/index.java index 6f49191f..a1aebcb2 100644 --- a/runtime/twodue/src/java/com/samskivert/twodue/logic/index.java +++ b/runtime/twodue/src/java/com/samskivert/twodue/logic/index.java @@ -1,5 +1,5 @@ // -// $Id: index.java,v 1.10 2003/05/21 02:40:13 mdb Exp $ +// $Id: index.java,v 1.11 2003/11/15 22:55:32 mdb Exp $ package com.samskivert.twodue.logic; @@ -94,40 +94,10 @@ public class index extends UserLogic ctx.put("error", "index.message.task_claimed"); } - // load up outstanding tasks and break them down by complexity - String expand = ParameterUtil.getParameter(req, "expand", false); - ctx.put("expand", expand); - - ArrayList tasks = null; - String query = ParameterUtil.getParameter(req, "query", false); - if (StringUtil.blank(query)) { - tasks = app.getRepository().loadTasks(); - } else { - ctx.put("query", query); - tasks = app.getRepository().findTasks(query); - // force expand to all - expand = "all"; - } - - // sort the tasks by priority, then complexity - Collections.sort(tasks, OPEN_PARATOR); - - CatList[] xtasks = categorize(tasks, expand, new Categorizer() { - public String category (Task task) { - return task.getPriorityName(); - } - }); - ctx.put("xtasks", xtasks); - ctx.put("xcats", new CategoryTool()); - - if (!StringUtil.blank(query) && xtasks.length == 0) { - ctx.put("error", "index.error.no_matching_tasks"); - } - // load up owned tasks and break them down by owner - tasks = app.getRepository().loadOwnedTasks(); + ArrayList tasks = app.getRepository().loadOwnedTasks(); Collections.sort(tasks, OWNED_PARATOR); - CatList[] otasks = categorize(tasks, null, new Categorizer() { + CatList[] otasks = categorize(tasks, new Categorizer() { public String category (Task task) { return task.owner; } @@ -154,7 +124,6 @@ public class index extends UserLogic { public String name; public ArrayList tasks; - public int pruned; public int compareTo (Object other) { return name.compareTo(((CatList)other).name); @@ -166,8 +135,7 @@ public class index extends UserLogic public String category (Task task); } - protected CatList[] categorize ( - ArrayList tasks, String expand, Categorizer catter) + protected CatList[] categorize (ArrayList tasks, Categorizer catter) { if (tasks == null) { return new CatList[0]; @@ -187,13 +155,7 @@ public class index extends UserLogic cats.add(clist); cmap.put(category, clist); } - if (expand == null || clist.tasks.size() < 2 || - expand.equals("all") || - (task.priority > 15) || expand.equals(category)) { - clist.tasks.add(task); - } else { - clist.pruned++; - } + clist.tasks.add(task); } CatList[] ctasks = new CatList[cats.size()]; diff --git a/runtime/twodue/src/java/com/samskivert/twodue/logic/tasks.java b/runtime/twodue/src/java/com/samskivert/twodue/logic/tasks.java new file mode 100644 index 00000000..9d77dc8a --- /dev/null +++ b/runtime/twodue/src/java/com/samskivert/twodue/logic/tasks.java @@ -0,0 +1,154 @@ +// +// $Id: tasks.java,v 1.1 2003/11/15 22:55:32 mdb Exp $ + +package com.samskivert.twodue.logic; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import javax.servlet.http.HttpServletRequest; + +import com.samskivert.util.StringUtil; + +import com.samskivert.servlet.RedirectException; +import com.samskivert.servlet.user.User; +import com.samskivert.servlet.util.ParameterUtil; +import com.samskivert.velocity.InvocationContext; + +import com.samskivert.twodue.Log; +import com.samskivert.twodue.TwoDueApp; +import com.samskivert.twodue.data.Task; + +/** + * Displays a summary of unclaimed tasks. + */ +public class tasks extends UserLogic +{ + public void invoke (InvocationContext ctx, TwoDueApp app, User user) + throws Exception + { + HttpServletRequest req = ctx.getRequest(); + + // display any message we've been asked to display + String msg = ParameterUtil.getParameter(req, "message", true); + if (!StringUtil.blank(msg)) { + ctx.put("error", msg); + } + + // we use this to determine whether to show "complete" buttons for + // tasks + ctx.put("username", user.username); + + ArrayList tasks = null; + String query = ParameterUtil.getParameter(req, "query", false); + if (StringUtil.blank(query)) { + tasks = app.getRepository().loadTasks(); + } else { + ctx.put("query", query); + tasks = app.getRepository().findTasks(query); + } + + // sort the tasks by priority, then complexity + Collections.sort(tasks, OPEN_PARATOR); + + CatList[] xtasks = categorize(tasks, new Categorizer() { + public String category (Task task) { + return task.getPriorityName(); + } + }); + ctx.put("xtasks", xtasks); + ctx.put("xcats", new CategoryTool()); + + if (!StringUtil.blank(query) && xtasks.length == 0) { + ctx.put("error", "index.error.no_matching_tasks"); + } + } + + protected static class CatList + implements Comparable + { + public String name; + public ArrayList tasks; + public int compareTo (Object other) + { + return name.compareTo(((CatList)other).name); + } + } + + protected static interface Categorizer + { + public String category (Task task); + } + + protected CatList[] categorize (ArrayList tasks, Categorizer catter) + { + if (tasks == null) { + return new CatList[0]; + } + + ArrayList cats = new ArrayList(); + HashMap cmap = new HashMap(); + int tcount = tasks.size(); + for (int ii = 0; ii < tcount; ii++) { + Task task = (Task)tasks.get(ii); + String category = catter.category(task); + CatList clist = (CatList)cmap.get(category); + if (clist == null) { + clist = new CatList(); + clist.name = category; + clist.tasks = new ArrayList(); + cats.add(clist); + cmap.put(category, clist); + } + clist.tasks.add(task); + } + + CatList[] ctasks = new CatList[cats.size()]; + cats.toArray(ctasks); + + return ctasks; + } + + protected static final Comparator OPEN_PARATOR = new Comparator() { + public int compare (Object o1, Object o2) { + Task t1 = (Task)o1, t2 = (Task)o2; + // sort first by reverse priority, then by complexity + if (t1.priority == t2.priority) { + return t1.getComplexityValue() - t2.getComplexityValue(); + } else { + return t2.priority - t1.priority; + } + } + }; + + protected static final Comparator OWNED_PARATOR = new Comparator() { + public int compare (Object o1, Object o2) { + Task t1 = (Task)o1, t2 = (Task)o2; + // sort by complexity + return t1.getComplexityValue() - t2.getComplexityValue(); + } + }; + + // used to easy category generation in UI + public static class CategoryTool + { + public boolean checkCategory (String category) + { + if (category.equals(_category)) { + return false; + } else { + _category = category; + return true; + } + } + + public void clear () + { + _category = null; + } + + protected String _category; + } +} diff --git a/runtime/twodue/web/app_footer.wm b/runtime/twodue/web/app_footer.wm index ecd4c8b4..bc49be3c 100644 --- a/runtime/twodue/web/app_footer.wm +++ b/runtime/twodue/web/app_footer.wm @@ -1,3 +1,5 @@ Two Due: $i18n.xlate("app_footer.summary_link") | +$i18n.xlate("app_footer.tasks_link") | +$i18n.xlate("app_footer.bycategory_link") | $i18n.xlate("app_footer.account_link") diff --git a/runtime/twodue/web/bycategory.wm b/runtime/twodue/web/bycategory.wm new file mode 100644 index 00000000..03217172 --- /dev/null +++ b/runtime/twodue/web/bycategory.wm @@ -0,0 +1,71 @@ +#set ($title = $i18n.xlate("index.title")) +#import ("/header.wm") + +

+ + + + + + + + + + +
Task summary By priority 
Filter:  Click the wrench to claim a task.
+ +

+ + +#if ($query) +Tasks matching '$query': +#else +Outstanding tasks: +#end + + +
+ + +#foreach ($xtask in $xtasks) +#if ($vidx == $break) +
+
  + +#else +#if ($vidx > 0) + +#end +#end + + + +$xcats.clear() +#foreach ($task in $xtask.tasks) + +#if ($xcats.checkCategory($task.complexity)) + +#set ($border = "") +#else +#set ($border = 'style="border-top: 1px solid"') +#end + + + + + + + +#end +#end +
 
$xtask.name 
$task.complexity
+Claim this task$task.summary   +[$task.creator] +#if (!$string.blank($task.notes)) +  [...] +#end +$task.getPriorityName() +Edit this task
+
+ +#import ("/footer.wm") diff --git a/runtime/twodue/web/header.wm b/runtime/twodue/web/header.wm index a4539a46..a5c48c51 100644 --- a/runtime/twodue/web/header.wm +++ b/runtime/twodue/web/header.wm @@ -3,6 +3,7 @@ ## These colors are used for common UI elements #set ($tcolor = "#99CCFF") #set ($scolor = "#CCCCCC") +#set ($fcolor = "#000000") diff --git a/runtime/twodue/web/index.wm b/runtime/twodue/web/index.wm index 9af1a1ca..248e6abe 100644 --- a/runtime/twodue/web/index.wm +++ b/runtime/twodue/web/index.wm @@ -4,7 +4,8 @@

- - - - - - - +

Browse:  by category +  by priority -

- - -
+
+ Owned tasks: @@ -12,7 +13,7 @@ #if ($vidx > 0) #end - + $ocats.clear() #foreach ($task in $otask.tasks) @@ -43,85 +44,10 @@ $ocats.clear() #end
 
$otask.name
$otask.name
-

-

Check the box to mark a task as completed.
-
  - -#if ($query) -Tasks matching '$query': -#else -Outstanding tasks: -#if ($expand == "all") -[trim] -#else -[show all] -#end -#end - - -#foreach ($xtask in $xtasks) -#if ($vidx > 0) - -#end - - - -$xcats.clear() -#foreach ($task in $xtask.tasks) - -#if ($xcats.checkCategory($task.complexity)) - -#set ($border = "") -#else -#set ($border = 'style="border-top: 1px solid"') -#end - - - - - - - -#end -#end -
 
$xtask.name -#if ($xtask.pruned > 0) -($xtask.pruned ...) -#else -  -#end -
$task.complexity
-Claim this task$task.summary   -[$task.creator] -#if (!$string.blank($task.notes)) -  [...] -#end -$task.getDisplayCategory() -Edit this task
- -

- - - -
Click the wrench to claim a task.
-Filter on single word:
- -
- - -
- -

 
Recent completed tasks: #foreach ($task in $dtasks) @@ -144,12 +70,10 @@ Filter on single word:
#end
-
  -Create new task: +

Create new task:

$form.fixedHidden("action", "create") @@ -187,13 +111,12 @@ $form.text("category", "size='10'", "")
+ $form.checkbox("claim", false) Claim created task   $form.checkbox("edit", false) Edit created task $form.submit("submit", "Create")
- diff --git a/runtime/twodue/web/tasks.wm b/runtime/twodue/web/tasks.wm new file mode 100644 index 00000000..0e960bee --- /dev/null +++ b/runtime/twodue/web/tasks.wm @@ -0,0 +1,71 @@ +#set ($title = $i18n.xlate("index.title")) +#import ("/header.wm") + +

+ + + + + + + + + + +
Task summary By category 
Filter:  Click the wrench to claim a task.
+ +

+ + +#if ($query) +Tasks matching '$query': +#else +Outstanding tasks: +#end + + +
+ + +#foreach ($xtask in $xtasks) +#if ($xtask.name == "On the list") +
+
  + +#else +#if ($vidx > 0) + +#end +#end + + + +$xcats.clear() +#foreach ($task in $xtask.tasks) + +#if ($xcats.checkCategory($task.complexity)) + +#set ($border = "") +#else +#set ($border = 'style="border-top: 1px solid"') +#end + + + + + + + +#end +#end +
 
$xtask.name 
$task.complexity
+Claim this task$task.summary   +[$task.creator] +#if (!$string.blank($task.notes)) +  [...] +#end +$task.getDisplayCategory() +Edit this task
+
+ +#import ("/footer.wm")