TODO SOONER: Make the person admin screen sort the roster into categories like the reports do. Make the person admin screen italicize or gray-out the invisible persons. Consider adding an "expert" flag to the user object to hide the helpful text. Clean up the CSS. Consider putting a percent calculating function in AttendanceHelper to do floating point math. TODO LATER: Check tab order on all input screens. Make it possible to add events without types. Make it possible to add persons without types. Add a field to the database to record who took attendance. Convert the passwords to encrypted hashes (use MySQL's PASSWORD function). Change the date box to use a little mini-calendar to select a date. Come up with a way to set a minimum width on a stretchable table. Implement a way to group events and roster entries and allow only certain users to view/edit them. This would make the system usable by a large institution with many attendance-takers (e.g. a school). CLEANUP: Add a date formatting class that will override SimpleDateFormat, hide the format strings and correctly handly empty dates. CLEANUP: Move some of the text formatting code out of AttendanceHelper into classes in the servlet folder. Version 1.8.0 -- 5/1/2006 Removed the initialization parameters from the web.xml file and created a attendance.properties file that contains those values instead. This makes it much easier to access those values within the classes without passing a bunch of values up from the calling servlet. Added an Initialize class that will load on startup to load the Velocity and attendance properties files. Because Velocity is a singleton, initializing it once is enough. Removed the loadConfiguration() function from AttendanceServlet since Initialize is now doing that work. Moved the Velocity-specific classes from the servlet package into their own velocity package. Updated the INSTALL.txt file to contain instructions to update the properties file instead of the web.xml file. Added an UPGRADING.txt to provide upgrading instructions for users who aren't developers of this package. Moved the email-sending code from AttendanceUser to AttendanceHelper to make it more easily reusable. Renamed AttendanceUser.sendReminderEmail() to sendPasswordReminderEmail(), changed it to call AttendanceHelper.sendEmail() and to use a Velocity template for its email content. Changed the procedure for preventing multiple submissions to include a hidden field with a unique value. The value is saved after a new record is created and compared with the next submission. If the values match, the save is not carried out. Removed the instructions from INSTALL.txt to edit the attendance.sql file. Changed the copyright dates at the top of all the source code files to 2006. Changed the values of the user type flags to not conflict with the calendar code. Added AttendanceHelper.log() to provide a centralized logging facility. Added iCalendarServlet.java to provide an iCalendar format export of the birthdays on the roster. Changed DumpCache to be started by Initialize and moved the dump_interval_msecs value from web.xml to attendance.properties. Fixed typos in the CSS files (wrong comment block delimiters). Changed the category admin to prevent deleting a category that contains events. Changed Category.save() to take ownership of any events without categories, in case their categories were somehow deleted. Version 1.7.0 -- 10/26/2005 Changed the names of the leakytent packages referenced through reflection. This only affects the attendance code if it is running as part of the leakytent system. Moved the version.txt file into templates/attendance and provided a soft link to it in the website root. Changed AttendanceHelper.getDatabaseConnection() and AttendanceHelper.putDatabaseConnection() to be non-static. Added an interface named Helper that defines get/putDatabaseConnection() and changed AttendanceHelper to implement it. Changed all internal uses of AttendanceHelper to use an instance of Helper instead of calling static functions on AttendanceHelper. This required changing all the constructors to accept a Helper parameter, all instantiations to pass along the Helper variable and most static functions to accept a Helper parameter. Changed all compareTo() functions to use "target_object instanceof CLASS" instead of "this.getClass().equals(target_object.getClass())". Fixed DumpCache.run() to actually run more than once using a while() loop, instead of just running once and exiting. Renamed the AttendanceRecord class to just Record. Prefixing the names of classes with "Attendance" is a way to show an implementation of an interface, which Record is not. Renamed the User class to AttendanceUser. Added an interface named User that defines all of the public methods and changed AttendanceUser to implement it. The biggest change this forces is that load() and friends are no longer static. Removed all of the reflection code from AttendanceServlet to find and use the User class and changed it to call the User interface instead. This simplifies the code quite a bit. Removed several wrapper functions from AttendanceUser that were only present to provide an object parameter instead of a basic data type. Now that the class isn't being used through reflection, the wrappers aren't needed any more. Changed all of the classes to use a centralized, overridable caching system. This allows caches that index on more than just the database sort order. Added some static strings to the AttendanceHelper class to provide global definitions for date formats. Removed split() and replace() from AttendanceHelper and changed all their references to use String.split() and String.replaceAll() instead. Closed a small security hole in AttendanceServlet where a cleverly crafted request from an unauthorized user could have revealed the email addresses and names of all the users in the database. Moved the static string constants from AttendanceHelper to Helper. Added a check to display an error message if the current site is not valid. When the attendance system runs standalone, the error should never be displayed. Added the JAR files for Jakarta Commons Collections, Log4J and MySQL Connector/J to the WEB-INF/lib directory. To comply with the Apache license, the Apache license and a NOTES file were added to the documentation folder. Corrected the INSTALL.TXT file to remove download instructions for the included packages and indicate that the JavaMail API and JavaBeans Activation Framework need to be downloaded and installed. Removed the text "Portions Copyright (C)2004 lookandfeel new media" from each java file, since the only lookandfeel code is in the com.lookandfeel.guid.jar file. Changed the copyright notice at the top of each file to specify that the code is only available under the GNU GPL version 2. Changed the value of the "form_action" context variable to come from an init parameter instead of being hardcoded to "attendance". Changed all save and delete actions in the admin tool to use a redirect page so refreshing the "Saved!" and "Deleted!" messages won't try to repeat the action. Version 1.6.1 -- 6/7/2005 Moved the GUID generation code into a JAR file. Changed the values of the user type flags (again) to make "NONE" use a non-zero value. Renamed attendance_admin_user_admin.vm to admin_user_admin.vm, attendance_admin_user_edit.vm to admin_user_edit.vm and attendance_admin_main_menu.vm to main_menu.vm. Renamed attendance_login.vm to login.vm. Changed AdminServlet to use the new template names. Changed the name of the velocity variable for AttendanceHelper to just "helper". Renamed the "attendance_event_type" table to "category". Renamed the "EventType" class to "Category". Added the "parent_category_id" and "prefix" columns to the "category" table and changed the "Category" class to load and save them. Renamed the "attendance_event_edit.vm" and "attendance_event_admin.vm" templates to "admin_event_edit.vm" and "admin_event_admin.vm", respectively. Changed AttendanceServlet to load and save multi-level categories like the Calendar does. Moved all of the "attendance_"-prefixed templates into a folder named "attendance" and removed the prefix. Fixed a small logic problem that prevented events from being saved if the roster was empty. Added a feature that will automatically create an admin login if no users exist in the database. The login will have the email address "admin@example.com" and the password "admin". Added a feature to force the user to change the default admin login's email address and/or password. This also prevents the admin from setting a user's email address and password to match the default settings. Added an INSTALL.txt file. I'm not sure why I didn't do this before I put this project on Freshmeat... Added a version.txt file to indicate what version is installed. Version 1.6.0 -- 5/30/2005 Added a copyright notice to the top of each template file. Renamed the attendance_user table to just user. Added theme_id and guest_account columns to the user table to make it match the user table from the calendar application. Changed AttendanceServlet.handleRequest to use reflection to find the User class and its methods and fields so it can use the com.leakytent.authentication package if it is present, otherwise fall back to the User class from the org.silence.attendance package. Changed the User types to bitmaskable flags so they can be combined in one field with the user types from the calendar system. Removed the obsolete JSP implementation. Version 1.5.1 -- 5/17/2005 Added the function getValid() to AttendanceRecord that returns true if the Person and Event references have been set, false otherwise. Changed Person.getAttendance() to always return an AttendanceRecord object. Changed templates/attendance_attendance.vm to check AttendanceRecord.getValid() instead of checking to see if the object reference is null (since Velocity doesn't handle #setting nulls very well). Fixed AttendanceServlet to always create an AttendanceRecord for a visible person, even if they are not present. This bug was keeping the new checkbox-based form from saving correctly. Version 1.5.0 -- 5/13/2005 Changed the authentication system to use email addresses instead of usernames. Changed all instances of Vector to ArrayList. ArrayList does the same thing but doesn't have the overhead of internal synchronization. Added a servlet to periodically dump the caches from a worker thread. Added a copyright notice to the tops of all the source files. Converted the JSPs to a servlet-based implementation using Velocity. Added a worker thread to dump the caches once a day. Changed all of the references to database connections to go through getDatabaseConnection() and putDatabaseConnection() in AttendanceHelper instead of opening and closing connections everywhere. This will make it easier to (someday) implement connection pooling. Added "forgot my password" feature. Added a "save and take attendance" button to the event edit screen to make it easier to add new events and immediately take attendance. Moved the "logged in as" information to the upper-right corner of each screen with a "logout" link to match the calendar system's interface. Added a "report generated on" line to the reports to make them more usable when printed. Changed the reports to show the date range being used rather than falling back on "beginning" and "present". Changed the event admin screen to stop the user from attempting to create or edit events when no event types exist. Changed the person admin screen to stop the user from attempting to create or edit persons when no person types exist. Fixed an oversight in PersonType.delete() that wasn't deleting the attendance records of the persons it deleted and wasn't dumping the Person cache. Added some checks to the attendance-taking interface to show an error message if the roster is empty. Changed the attendance screen to use a yes/no (checkbox) for the Present column instead of a dropdown with Yes, No and N/A. N/A is now implied if the record is saved when the person is not visible. This change can easily be reversed if necessary. Renamed all of the template files to use the prefix "attendance_" to make integration with the calendar system easier. Added an "edit profile" button to the main menu so non-admin users can change their password and update their profile. Changed User.setEmailAddress() to check to ensure the new email address is unique. Fixed an oversight in EventType.delete() that wasn't dumping the Event cache after deleting the events of that type. Changed all of the database tables to use the prefix "attendance_" to make integration with the calendar system easier. Version 1.4.0 -- 3/29/2005 Added a "Pragma: no-cache" header to the top of each page to prevent browser caching. Slightly cleaned up the HTML in templates/user_edit.jsp. Changed the "Last seen" report to calculate the amount of time since the last event each person attended. This is shown as a comment under the date reading "x years, x months, x weeks and x days ago". Changed the "Person" report to show the last event the person attended and the time since that event, similar to what the "Last seen" report shows. Version 1.3.0 -- 3/1/2005 Moved the "Event type" and "Event attributes" buttons from the main menu to the event admin screen. Fixed a small bug in EventType that wasn't initializing highlight_percentage when the object was created. Added a "type" field to the Person records so they can be grouped in the reports and on the attendance screen. Added a "Person type" admin section. Version 1.2.0 -- 2/28/2005 Fixed a typo in the attendance.sql file that creates the database tables. Added the field "highlight_percentage" to the "event_type" table. Changed the event types to allow the user to set the percentage at which the attendance numbers are highlighted in reports. Previously, the numbers were always highlighted when the attendance was 50% or more. Version 1.1.0 -- 2/22/2005 Cleaned up a few places in the class files that were closing Statements without first closing their ResultSets. Added getTotal() to Event.java to give the number of persons present and not present at a given event. Added getTotal() to Attribute.java to give the number of persons present with the attribute set at a given event. Changed the "Last seen" report to sort by date, then by name. Changed the event admin screen to provide totals (percent/number) of persons present (including non-visible persons). Changed the attendance screen to provide totals (percent/number) of persons present and their attributes. Changed the attendance screen to add a "Save attendance and refresh" so the user has a way to commit records and stay on the same screen. Changed the attendance screen to show non-visible persons if they have an attendance record for that event. Added a new report: "Person Report". This report breaks out an individual person's attendance by type (with percentages/numbers) and also lists all of the events a person has ever attended. Added an option to "Remember me" that will set the auth cookie's lifetime to one year instead of always using a session cookie. Changed the "menu button" links into real SUBMIT buttons. The old style looked cool but they didn't always display correctly and they were hard to click in some cases. Optimized all of the screens and reports to display readably on a Treo 600. Fixed a few typos and made some miscellaneous layout changes. Version 1.0.0 -- 2/10/2005 Initial verison.