Introduction to programming for the Web: We're going to start out with something small here. We'll just have a sample registration page for creating users on our site.The prospective user enters his or her name, address and other details and clicks on "register me" button on the browser. We are going to implement the whole process of capturing this information and creating a user and sending an email back to the user informing whether registration was accepted or not. Let us suppose that we require only the following limited information to register a user: User's Name Login name Email Address The HTML for this page might resemble the following: ============================================ Registration Page

Please enter the following, to register

Your Name:
Your Email:
Prefered Login Name

We can copy this and paste it in a file in caravan's document path. Let this file be named "register.html". When you enter the url http://localhost/register.html in your browser location and press enter, you should see this registration form. If you had copied this in the caravan's template path instead, there will be no difference. You will see exactly the same thing. But internally caravan would have served it by running the compiled code from memory. This is because any file with "html" extension in the template path is automatically compiled by caravan at startup (and recompiled if modified at runtime). This page contains no dynamically generated information and the compiled code probably just contains one instruction to dump this entire page, stored as a string, from caravan's internal registers. So, a static document will be cached in caravan's internal memory if it is located in the template path, though normally it is best to put static documents in the document path -- it will not take up any memory this way. Note : if we just copy any file in the template path at runtime it will not be active until caravan is restarted -- you have to use the caravan's interface to make a new source file active at run time. Let's go over this HTML carefully as there are a variety of tags that you may not be familiar with. First, let's take a close look at the
tag which may look like: or or The form tag tells the browser that this is the start of a form which will be used to submit data to a Web server. The 'action' attribute's value tells the browser which resource the form is being submitted to. This can be a relative or absolute link, just like an anchor tag, an img tag, or any of a number of tags that identify a resource to the browser. In our design we have decided to use the "registerme.html" dynamic caravan page. The 'method' attribute's value, for this form, is POST. For Web-based forms, you will generally use a POST or a GET method. As mentioned previously, the GET method will send the form's data in the query string (embedded in the URL) and the POST method will send the data in the body of the request, after the headers. If POST data is sent, the form of the data depends upon the 'enctype' attribute, which we will discuss next. The 'enctype', attribute's value, for this form, is 'application/x-www-form-urlencoded'. For this enctype, you can actually leave off the attribute as this is the default encoding type for a Web form. When this type is specified for POST data, the data is encoded just as it would be for the query string (name/value pairs with special characters converted to their hexadecimal equivalent, joined by and equals sign, with respective pairs joined by an ampersand). Then, after the headers are sent, the body of the document has the form data. There is another common 'enctype', however, which is 'multipart/form-data'. This is usually used for file uploads, as trying to encode the file data would be difficult, at best, and grossly bloat the size of the data sent. Now, let's look at the 'input' tags: The above tags will create input boxes. The 'type' attribute tells the browser the type of input box to display. The 'size' and 'maxlength' attributes specify the size of the box and the maximum number of characters that may be typed in it. The 'name' attribute is the name that will be used to reference this data. There are other tags like checkbox, radio, select etc which can be used in the form. By now, you should have a general understanding of what the attributes mean, so I won't discuss them. However, it's important to know an important difference in how these form elements are handled. For most form elements, if no value is supplied, the browser will send the name, followed by an equals sign, but with no value. For checkboxes, the name of the form element is not sent if it is not checked. Further, if a value is not specified, the value of 'On' will automatically be supplied. The last two form elements are the 'Submit' and 'Reset' buttons: The submit button is what actually causes the form data to be encoded and sent to the server. The reset button merely resets the form to its default state and plays no role in our exercise. Here the submitted value can be referenced using the name "click". It is generally usefull to give names to the buttons, if there are multiple buttons, to know which button was pressed by the user. Browser will only send the value of the button that was pressed. Now we have some idea about how to create a form in HTML, there are also other ways to submit data to the server, only the method of generation of the form is different. To the server all forms look exactly the same. Now when this request reaches the server, it will run the dynamic document "registerme.html" in a seperate transient thread. Before that we have to write the script "registerme.html" and put it in the template path of caravan. We have to create a new user with the information we have, and tell the user the result of this operation. In caravan we cannot create a user from any domain, only the admin domain has the priveleges to create a new user. So when we get this request we will save the details in a table and put it into a queue. This will fire an eventhandler which has the priveleges of admin. In Caravan schedulers and eventhandlers run with the highest privelege. Alternately we could have a scheduler to look into this task periodically and and do the user creation. The difference is that event-handlers wake up when the expected event occurs and are instantaneus in their response, while schedulers wake up periodically and see if anything needs to be done -- if you need a backup every sunday a scheduler can do this. There are also situations where both schedulers and eventhandlers are needed to accomplish some tasks. We can also fire an email to an admin and wait for him/her to register the user -- this is what is desired in a real situation, since accepting a user usually involes some consideration. In our case we dont have much information to go by, so we will just create the user and hope for the best. At runtime a caravan script has some objects passed to it by the server which contains the information about the request. Invariably an object named "request" is available which gives some information about the caravan's setup and requester's address, the server ip etc. When data is being submitted to the server an object named "form" will also be available. Our code in registerme.html is expecting a form. We will write this code now: if form; user newuser; newuser(userid)=form(login) if newuser(uid)="0"; table users=test.users; users(username)=form(username) users(login)=form(login) users(email)=form(email) users(uid)="0" users(insert) queue myq(makeuser) myq(item)=users(recordno) "Thank you for registering ";form(username);"! Your request is being processed, you will be notified by email" else "Your requested login name is not available, Please try a different one!" endif else; "Sorry no data, Please try again!"; endif What you see here is an example of caravan script embedded in an HTML document. The stuff in between and tag is the actual code, which caravan has already converted to its internal pseudo code at startup, so there is no compilation overhead everytime the page is accessed. The stuff outside the caravan tag is sent to browser as it is. In Caravan we have whole objects which represent some actual data. Every object has a type and a name, the type detemines its intrinsic behaviour and the name gives a handle to access the object's methods and properties. A script usually starts with one or two objects already created for it by the server. As mentioned before, these are named "request" and "form". The form object has properties with names which we have given in the HTML code in the begining -- ie username,login,email etc. We also have a table test.db which have fields named username, email and login. This is just for convenience, the table could have had totally different names. Line by we will go through this code: 1.if form; Before anything we check whether a form object exists to make sure that some data was indeed being passed to us. 2. user newuser; Create a user object. This object comes with the default user information of the user who is accessing this page. This page is run by a non-user so no info -- user property "uid" will be 0; 3. newuser(userid)=form(login); We try to select the user who has the requested userid. 4. if newuser(uid)="0"; The uid property has a unique numerical value greater than zero for a valid user. Zero indicates no such user exists. This is ok, we can accept the registration. 5. table users=test.users; We create a table object to represent the users.data table in test.db 6. users(username)=form(username) 7. users(login)=form(login) 8. users(email)=form(email) Assign the various details to the table's fields.We are using the same fieldnames for both table and form here. 9. users(insert) Inserts a new record. Table's recordno is now set to the new record just created. 10. queue myq(makeuser); Create a queue object which is identified the name 'makeuser'. The queue variable is named 'myq' here. 11. myq(item)=users(recordno); Put the new record into the queue. You can put anything into the queue including whole objects. Your event handler will pick it up later. 12. "Thank you for registering ";form(username);"! Your request is being processed, you will be notified by email" The quoted strings are floating data which gets flushed to the browser. The user's name is also inserted in between the two quoted strings. This is how dynamic information is sent to the browser. 13. else A user with login exists, so we will ask the prospective user to choose another login 15. "Your requested login name is not available, Please try a different one!" 16. endif;// end of second if 17. else; There was no form, so we just say something 18. "Sorry no data, Please try again!"; 19. endif;// end of first if We have done what needed to be done immediately, and left the task of creating the user to the event-handler. The new user knows his userid is being created and is expecting a mail to that effect. Now we have to create the event-handler that does the actual work. An event handler is nothing but another caravan program. This code is running in a different thread and sleeping mostly, waking up only when the event occurs. Here is the code for the event-handler: eventhandler(makeuser) table users=test.users users(recordNo)=_event(item) user newuser newuser(userid)=users(login) if newuser(uid)="0" newuser(username)=users(username) newuser(domain)="freeuser" newuser(link)=users(recordno) newuser(add) users(uid)=newuser(uid) mail mx mx(to)=users(email) mx(subject)="Congratulations!, you are now a user on our freeuser domain" mx(text)="Please login with login name :" mx(text(01))+=users(login) mx(text(01))+=" " mx(text(01))+="and \"password\" to our service." mx(text(01))+="\r\n" mx(text(01))+"Be sure to change your password, by going to password.html" mx(text(01))+="\r\n" else mail mx mx(to)=users(email) mx(subject)="Sorry,Could not create your login. pls choose another and try again!" users(deleterecord);// this user is rejeced endif _event(DeleteItem) The new things in the above code is explained here: 1. eventhandler(makeuser) An eventhandler is created by the declaration 'eventhandler(eventname)'. All statements before this declaration is executed only once when the eventhandler is registered by caravan. An eventhandler is registered when it is executed the first time, automatically at startup. The statements after the 'eventhandler' declaration is what gets executed everytime this event occurs. An event is generated automatically when something is put into the queue. The eventhandler file is also in the templates path of caravan. If you modify or create an eventhandler at runtime, it has to be registered by explicity executing it once through a browser request. An eventhandler starts with the object '_event' of type queue. This is like having an invisible statement at the beginning of eventhandler code: queue _event(eventname) 2. users(recordno)=_event(item) Remember, we had put the recordno from test.users into the 'makeuser' queue. Now we retrieve this value from queue, so we can go back to the record we are interested in. 3. The following code adds a new user to caravan. user newuser;// creates a user object of name newuser newuser(userid)=users(login);// assigns the new userid if newuser(uid)="0";// check for existing user with same login .. we had checked this before, but // make sure that the login-name has not been taken in the meanwhile. newuser(username)=users(username);//assign the username newuser(domain)="freeuser";// set privelges as per freeuser newuser(link)=users(recordno);// a this is to link the two tables newuser(add);// adds a new user The caravan user table holds only the details needed to login and provide some basic access. The application programmer needs to maintain another table for more details, ie. address, email etc. The 'link' property of user object provides the link between the two tables. This will become clear when we create the code which creates the user's login page. 4. mail mx mx(to)=users(email) mx(subject)="Sorry,Could not create your login. pls choose another and try again!" Object of type mail is assigned its various properties. The mail object is sent automatically. More about Mail and SMTP in another document. 5. _event(deleteitem) If the current item is not deleted, the eventhandler will repeat the operation after some interval, and wont proceed to the next item. We dont want that here. As mentioned earlier we could have done this job in a scheduler too. For this we would need to declare a scheduler. Creating a scheduler: ================ You can create a scheduler by adding a schedule statement anywhere in the code, only the first schedule statement is used, the rest are ignored. Schedule = (=,...,&......&=,..,[&count=nnn]) Here timespec keywords are minute,hour,day,date,month,year; Values are those within the valid range for any timespec or "all". The interval is minimum 1 minute. count gives the maximum number of times the scheduler should run. Examples of scheduling; Schedule = (day=sun); //once every sunday Schedule = (minute=all); //once every minute Schedule = (minute=all&count=1); //at startup only Schedule =(minute=0,15,30,45); //four times every hour Schedule =(hour=10) ; //ten o clock every day Schedule =(date=1&month=1); //on 1st jan at 0000 hrs every year We need to schedule the task to run every hour or so, so we will use Schedule=(minute=1); Here is the code if one had to do the user creation in a scheduler: schedule=(minute=1); table users=test.users select from users where uid=0 loop newuserlist (users(selected));// loop through the new users who have registered during the interval user newuser newuser(userid)=users(login) if newuser(uid)="0" newuser(username)=users(username) newuser(domain)="freeuser" newuser(link)=users(recordno) newuser(add) users(uid)=newuser(uid) users(modify) mail mx mx(to)=users(email) mx(subject)="Congratulations!, you are now a user on our freeuser domain" mx(text)="Please login with login name :" mx(text(01))+=users(login) mx(text(01))+=" " mx(text(01))+="and \"password\" to our service." mx(text(01))+="\r\n" mx(text(01))+"Be sure to change your password, by going to password.html" mx(text(01))+="\r\n" users(nextrecord);// check next new entry else mail mx mx(to)=users(email) mx(subject)="Sorry,Could not create your login. pls choose another and try again!" users(deleterecord);// this user is rejeced, delete and go to next record endif loop newuserlist 128;// do max 128 new users at a time This completes our task of creating the user, now we need to give the user a login page. The following is a sample login page for user with "freeuser" domain: We will study it as illustrates some important concepts. domain freeuser table users=test.users "

Hi,";users(username);" (";users(email);")

" "Welcome to free services at our site
" "blah blah etc"
We will just go through the new statements: 1. Domain freeuser The domain statement controls the access to this page. Only users with 'freeuser' domain can access this page. In case you are not logged in, caravan automatically prompts for login. One can also give access to multiple domains by listing the names of priveleged domains seperated by '|' after the 'domain' keyword : Domain freeuser|admin ;// gives access to 'freeuser's and 'admin's. 2. users(recordno)=userinfo(link) A valid user has a persistent object named 'userinfo' , which holds the 'username','link' and 'domain' properties of the user.Here we are accessing the user's record for more information, using the link which was set while creation. 3. "

Hi,";userinfo(username);" (";users(email);")

" The 'email' property of the user is retrieved from the table. This completes our process of registering, creating and giving access to a user on our site.