TF-Login is a login,registration, and user account management package for Seaside.
I have been constructing a web application that allows users to maintain a checklist of to-do items. In an effort to keep the barrier to entry as low as possible and entice new visitors to try the application, new visitors are allowed to create and manipulate a checklist without first logging in.
The new users are informed that for their content to be available to them on their next visit, they must register for a free account before they leave.
The trick here is how to save the content that they have already created (i.e. their checklist) and associate it with them so that after they have registered it can be made available to them in a seamless fashion. This is particularly interesting if registration involves email confirmation which will occur in a new Seaside session. And of course if the new user fails to confirm their registration, their saved content should be eventually discarded.
The TF-Login solution - #onRegistration:
TF-Login has features that make addressing this a straightforward process.
The TLLoginComponent has a method #onRegistration: to which you can supply a block to be evaluated before the registration email is sent. (Email confirmation may be enabled or disabled from the Seaside configuration page for the application.) If the result of the block evaluation is false, the registration process is aborted. That's not what is needed in this case, so we'll always return true.
The block is passed a single argument: a PendingUser object. This is the object that TF-Login will use to construct the RegisteredUser object that will be created and saved when the user navigates to address provided in the registration confirmation email.
We will insert the current checklist information into the applicationProperties dictionary of the PendingUser object. Then when the user logs in for the first time after confirming their registration, theat same checklist information will be available from the TLUser object's applicationProperties dictionary. The TLUser object for the currently logged in user is obtained like this from within a WAComponent in an application making use of TF-Login:
self session user.
If the user fails to confirm their registration, the checklist information stored in the PendingUser object's applicationProperties dictionary will be discarded along with the PendingUser object after the confirmation timeout period has expired. (The confirmation timeout period can be set in the Seaside application configuration page.)
Here's what the onRegistration block might look like:
loginComponent onRegistration: [ aPendingUser |
put: self checklistInfo.
A nice side benefit of saving user-specific data in the user object's applicationDictionary is that it can be easily persisted when it has changed using the TLLoginComponent>>#saveUser method. TF-Login saves the user object including its applicationProperties dictionary using the current storage adaptor. The default storage adaptor provided with TF-Login saves user objects in individual files and scales easily to 100,000 users.
My next problem was how to handle synchronization of the checklist information when the user logged in more than once concurrently. But that's a topic for another article...