|
|
||||||||||||||||||
|
|
||||||||||||||||||
![]() |
![]() |
Issue 6 - Revision 8 / January 18, 2003
|
|||
|
Customized User Folders Revisited - Another look - - - - - - - - - - - - By Kristoph Kirchner | December 15, 2003 A short while ago, a ZopeMag reader suggested that I continue the 'Customized UserFolder' series by showing how writing your own UserFolder can help you provide user-specific content. This article gives some examples of this: for example, how to send mails containing News compilations to users who have asked to receive News items in certain pre-defined categories. first article IntroductionThe following article is meant for intermediate Zope users and those who are new to working with Zope together with a database and is meant to demonstrate how easy it is to create personalized Websites with Zope. This is done using a revised version of DBUserFolder (which was the topic of part two of the Customized User Folders series), i.e. a UserFolder that stored the user data in a database (in this case: MS Access). In the first article we simply expanded the default Zope user folder by adding certain properties to it. In the second article we described how to store user data in an external database. This is useful when other applications have to have access to the user data. Further, more complex queries are possible and backing up the data is easier with a database. The present article expands on the previous one by giving examples for use of such customized user folders together with a database. For the examples below you will need the revised DBUserFolder, which you can download here. The zipped file also contains zexp-files of the code examples described in this article. The earlier version of the DBUserFolder product used a table called UserTable. The new version uses a modified table of the same name, as well as several other tables. In the zip file you will find a file readme.txt which describes how to proceed with the examples, as well as a description of the tables. First, let me shortly describe the three examples: The first example shows how a programmmer can design a Webpage using different stylesheets depending on which stylesheets users have selected from a pre-defined list. The stylesheets are DTML Documents in Zope (called, for example, default.css). For each stylesheet there is an entry in a table Stylesheets. This table defines a unique ID, a name and a filename for each stylesheet. The reason I call it a "fantasy" is because the mechanisms for this don't all exist in Zope 3X right now. But, I am confident that most of them will before a beta release. The second example shows how to send e-mails to users who have selected up to three categories from a list of News categories. Whenever a new News item is added to a category, all users that selected the respective News category in their preferences receive an e-mail with the News item's headline and intro. The third example describes how to render modules on a Webpage depending on which modules the logged-in user has selected from a list of available modules. The modules are defined in the database as HTML code containing TAL attributes. As mentioned above, in the examples to be described in detail below we want to create Webpages depending on options that a logged-in user has selected. For this we need some extra fields in the user table (as well as some more tables in the database).
The table UserTable contains five more fields now than the earlier version of the DBUserFolder, which only used the first eight fields shown in Table 1. The field Stylesheet contains a stylesheet id which corresponds to an id from the Stylesheets table (see Table 2). This is the same for the fields Pref1, Pref2 and Pref3, which correspond to ids from the table Categories. The Modules field contains a list of module ids corresponding to ids from the Modules table (see Table 4). This list is stored as a string and needs to be converted to a Python list to be of use.
The figure above shows the modified edit page for a DBUser. This edit page contains checkboxes which are dynamically created from the Categories table. From the checkboxes, a user can select up to three categories to subscribe to (in the above example there are only two categories). Whenever a News item is added to one of the selected categories, the user receives a corresponding e-mail. The Stylesheet drop-down menu is also created dynamically, this time from the Stylesheet table. The option values are the ids of the stylesheets, while the stylesheet names are shown in the menu (e.g. Default Stylesheet, New Stylesheet). The Modules section is a multiple selection list which again is created dynamically from a table in the database, the Modules table. User-specific StylesheetsAs mentioned above, for this example to work we need a table, which we have called Stylesheets, which contains the information about the various stylesheets available. Let's say this table contains the following two stylesheets:
Further, we have two DTML Documents called default.css and new.css in Zope, defining what links are supposed to look like when the respective stylesheet is used.
default.css:
a {font-family: Arial, Helvetica, sans-serif; font-size: 10px; }
new.css:
a {font-family: Times New Roman, serif; font-size: 12; }
The table UserTable contains a field called Stylesheet which holds the ID of a stylesheet. Using this field, we can retrieve the filename of the stylesheet selected from the Stylesheet table and use this filename in a Zope Page Template. Let's say we have a Page Template standard_template.pt, which defines a macro that is to be used by all other pages of the Website so that all pages will have the same look. This macro can be programmed so that it uses whatever stylesheet is defined in the user's Stylesheet field. The following listing shows such a macro:
In line 5 you can see that the href attribute of the link to the stylesheet is created using TAL. The tal:attributes expression makes use of a Python Script which is shown in the next listing:
The Python Script uses the Z SQL Method getUserQuery, which is defined in the acl_users folder. The Z SQL Method returns a user's data record (here of the user who is currently logged in, i.e. AUTHENTICATED_USER). If there is a record for the logged-in user, i.e. if the length of the Z SQL Method result is not zero, the value of the stylesheet field is stored in the variable userstylesheet. If the Z SQL Method returns no data record, e.g. if AUTHENTICATED_USER is the anonymous user or the logged-in user is not defined in the DBUserFolder, the variable userstylesheet is set to 0. This is necessary for the if-construct in line 8. If the variable userstylesheet contains a value other than 0, the Python Script returns the filename for the stylesheet id stored in userstylesheet using the Z SQL Method sql_getStylesheetByID (line 9), which is also defined in the acl_users folder. If userstylesheet contains 0, the Python Script returns the default stylesheet 'default.css'. When the macro is used in another Page Template, it calls the Python Script to see which stylesheet is to be used. Sending E-Mails to Interested UsersFor this example, let's say you have a News management system where you can add, edit and delete News items that consist of a headline, an intro text, a body text and a category. Now you want to give registered users of your Website the option of subscribing to up to three different News categories. Whenever a News item is added to a given category, an e-mail is to be sent to every registered user that has subscribed to the category. So, in the Python Script (or DTML Method or External Method, whichever you use) where the News item is actually created and stored, you need to insert the code that will send the e-mails. For example, in a Python Script you could use the following line to redirect the browser to a DTML Method we've called send_mails.
# send mail to everyone who's interested in this category
return container.REQUEST.RESPONSE.redirect('send_mails?catid='+str(category)+'&headline=
'+str(headline)+'&intro='+str(intro))
The easiest way to send e-mails in Zope is to use a DTML Method and the dtml-sendmail-tag. The following listing shows what the DTML Method send_mails could look like.
The important part of this code is in line 7. Here the Z SQL Method sql_getUsersByCategory (see Listing 4) is used to get all users that subscribed to the category for this News item. Iteration is performed through the list of users returned by the SQL query and their e-mail addresses are added to the to-line.
Since the categories that a user has subscribed to are stored in the three fields Pref1, Pref2 and Pref3, the Z SQL Method sql_getUsersByCategory has to reflect this and must return all users where the chosen category is stored in either the Pref1, the Pref2 or the Pref3 field (lines 5-7, Listing 4). Showing User-specific ModulesFor this example, we want to store module code in the database, retrieve it and render it on an index page. Let's say we have the following entry in the Modules table:
In order to retrieve the modules selected by a user, we need to retrieve the value of the Modules field from UserTable. As mentioned above, this field contains a list of the module ids as a string, e.g. '1,3,7'. To be useful, this string will have to be split into a list whenever the field is used. How this is done is shown in Listing 5 below. The following Python Script called py_getUserModules serves two purposes: 1) it returns the list of modules (line 15, Listing 5); and 2) it returns the 'Sourcecode' field of a specific module (line 20, Listing 5).
The Python Script has two parameters. The num parameter is used when a specific module is to be accessed. The flag parameter must be set to 1 if only the list of modules is to be returned. Let's take a closer look at the Python Script code: In line 5 we use the Z SQL Method getUserQuery of the acl_users folder to get the user record for the currently logged-in user. If there is a user (line 7), the value in the modules field is retrieved (line 8) and the string in the modules field is converted to a Python list using the split() method of the string module (line 9). Otherwise the list is empty (line 11). If the list is not empty (line 17), i.e. modules have been selected for this user, the Z SQL Method sql_getModuleByID is used to retrieve the module data record from the database depending on the num parameter (line 18). If there is a module with this specific id, its source code is returned (line 19). We can render the modules' source code on the index page as follows:
First, we use the Python Script to get the list of modules so we can iterate over the length of the list (line 2). Then we use it again to retrieve the source code of the current module (line 3). Since the source code contains TAL code and not just simple HTML code, it is not enough to use the word structure to render the code. As you can see in line 3, the source code for the module (which is the return value of the Python Script called here.py_getUserModules(num) ) is given as a parameter to talrenderer. talrenderer is an External Method that takes text, i.e. HTML and TAL code, and instantiates a Zope Page Template using this text. This leads to the TAL code being rendered when the Zope Page Template is returned, as shown in Listing 7.
I hope these examples have given you some idea of what you can do with a customized user folder. This is of course only a small selection of what is possible, and there are also various ways of achieving what I've done here. The main goal of this article was to show how to provide user-specific content. This article and its examples were inspired by John Tynan. I thank John for his interest and his positive feedback to my earlier articles and hope this one contains what he had in mind for a follow-up. Further Resources
Download .ZIP of Customized UserFolder:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ZopeMag is committed to bringing you the best in Zope Documentation. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Reproduction of material from any of ZopeMag's pages without prior written permission is strictly prohibited. Copyright 2003 - 2005 ZopeMag |
|