Web Crossing Server-side JavaScript

Creating users and setting user properties

Introduction
About setUserProperties
A Sample Data File
The JavaScript Source
Testing setUserProperties
How it Works
Where to Go from Here
Troubleshooting
Resources

Introduction

In the previous section, we learned more about Web Crossing objects, and how they can be used in Web Crossing's server-side JavaScript (WCJS). We saw there are objects for all of Web Crossing's basic data types, including folders, discussions, links, chat rooms, messages and users. We also learned how to open a user object, check properties of a user object and add/change a user's properties.

In this section we will look at a small, but very powerful and flexible example function called setUserProperties that reads data from a comma-delimited file (for example, a Microsoft Excel .csv file) containing a list of users, property names and property values and accomplishes the following tasks:

Using setUserProperties you can maintain a database of your users and properties off-line and make and change properties conveniently.

About setUserProperties

Caution: The setUserProperties function is provided here as a learning example. Because it is a small example, safety features (such as validation of correctly formatted data) have been left out. This function can overwrite the existing property values of current users, including passwords, and can be used to add new users to your system. Please use this function entirely at your own risk. Until you understand how the function works, it is strongly recommended that you experiment first with a test server, rather than with your main production server. A backup of your Web Crossing server before using setUserProperties on your production server is also strongly recommended.

To use setUserProperties, you must first create a comma-delimited text file containing the data you wish to set. Microsoft Excel .csv files are convenient for creating your data file, although any ordinary text editor may be used.

The format of the comma-delimited file is as follows:

When setUserProperties is invoked, the data is input, and the userName is looked up in the Web Crossing database to see if that user exists or not. If no user exists with the specified name, the user is automatically created.

The specified user's properties are then updated (overwritten) or created, as needed. Already-existing properties in the Web Crossing database which are not specified in the data file are left unchanged. In other words, you don't have to create a data file containing all the user properties - just those you want to change or create.

Let's try the function to see it in action before we explain how it works.

Sample Data

Here is some sample data you can use for testing. Create a file with the filename students.csv and enter the following data in it:

this file registers new users for Big U University
studentID,userType,fullName,sex,userEmail,dataCreated,userPassword
kobayashi,3,Kobayashi Hiroichi,1,koba@bigu.ac.jp,2000/09/03,iggi
kurata,3,Kurata Masao,1,kurata@bigu.ac.jp,2000/09/03,agga
matsumoto,3,Matsumoto Eriko,2,matsumoto@bigu.ac.jp,2000/09/03,oggo
yokozawa,3,Yokozawa Nobuo,1,yokozawa@bigu.ac.jp,2000/09/03,umma

The studentID property name is ignored because it is the property name in the first column. The data in the first column always becomes userName (the Web Crossing user name).

The properties userType, fullName, sex, and dataCreated are custom property names.

The properties userEmail and userPassword are standard property names.

The JavaScript Source

Next create a file called setuserproperties.tpl and input the following WCJS function into the file:

%% command setUserProperties() {
var dataFile = form.data;
if (wctlEval('"' + dataFile + '"' + '.fileExists') !=1) { // file exists?
+ '(' + dataFile + ')' + " does not exist<BR>";
return;
}
+'<HTML><BODY BGCOLOR="#FFFFFF">';
var dataInput = wctlEval('"' + dataFile + '"' + '.fileRead()');
+ "data successfully read <P> " ;
var dataRecords = dataInput.split("\r");
var records = dataRecords.length;
+ records-2 + " records of data read <P>" ;
var propertiesList = dataRecords[1].split(",");
var nProperties = propertiesList.length;
for (var i=2; i<records; i++) { // start with row two
var record = dataRecords[i]Split(",");
var curUser = User.lookup(record[0]);
+ '<P>';
if (curUser == null) {
+ "User" + record[0] + " is not registered - Will automatically register. <BR>";
curUser = new User(record[0]);
}
+ "User " + record[0] + " is registered.<BR>";
var confmsg = "User: " + record[0];
for (var j=1; j<nProperties; j++) {
curUser[propertiesList[j]] = record[j];
confmsg += " " + propertiesList[j] + ": " + record[j];
}
+ confmsg + "<BR>";
}
+ 'Done<BR>';
+ '<BODY></HTML>';
} %%

Testing setUserProperties

To test the setUserProperties function, move the files you created (students.csv and setuserproperties.tpl) to your webxTemplates directory, edit your webx.tpl file to include setuserproperties.tpl and reset the file cache in the Control Panel.

Note: For details on editing your webx.tpl file and resetting the file cache, see the section on JavaScript functions.

Now you are ready to invoke the function using the following special URL syntax:

http://yourdomain.com/webx?setUserProperties@@!data=students.csv

Just replace the part of the URL highlighted in red with your own domain and script name.

When the function is invoked, the response page will report all the users it created and the properties set for existing and new users.

How it Works

Let's look at setUserProperties in detail to see how this works.

%% command setUserProperties() {

First, we define setUserProperties as a command (rather than as a function) so we can invoke it from a URL.


var dataFile = form.data;

The name of the datafile is stored in a local variable.


if (wctlEval('"' + dataFile + '"' + '.fileExists') !=1) { // file exists?
+ '(' + dataFile + ')' + " does not exist<BR>";
return;
}

WCJS does not have its own file I/O functions, so we use the WCTL fileExists command to check to make sure that the data file we specified exists. If the file does not exist, we append a suitable error message to the response page and immediately return from the function.

You can use WCTL expressions inside WCJS with the wctlEval function.

The // symbols indicate that the rest of the line is a comment.


+'<HTML><BODY BGCOLOR="#FFFFFF">';

If the file exists, we append formal HTML tags to the response page, so we can set the background color (and other page attributes you might want to set).


var dataInput = wctlEval('"' + dataFile + '"' + '.fileRead()');
+ "data successfully read <P> " ;

We again use a WCTL command - fileRead - to read the contents of our comma-delimited file into the local variable dataInput. This variable now contains the contents of our data file as one character string.


var dataRecords = dataInput.split("\r");

We use the JavaScript core method split to convert dataInput into an array of records, using the linebreak characters in each line of the data file as a record delimiter. This new array is stored in the local variable dataRecords. WCJS supports all JavaScript core methods.


var records = dataRecords.length;

Here we use the JavaScript core method length to count the number of records in the file we read in. We store this value in the local variable records.


+ records-2 + " records of data read <P>" ;

Here we append the number of data records we input to the response page. The reason we report records-2 instead of records is because the first two records contain the comment line and the line of property names.


var propertiesList = dataRecords[1]Split(",");

We again use split to create an array. This time we use comma (,) as a delimiter and break up dataRecords[1] (the first element of the dataRecords array) into an array of property names. We store this array in the local variable propertiesList. (Note that we didn't do anything at all with dataRecords[0] because it just contains comments that we don't intend to use anywhere.)


var nProperties = propertiesList.length;

We use the core JavaScript method length to count the number of properties and store this number in the local variable nProperties.


for (var i=2; i<records; i++) { // start with row two

Here we begin a JavaScript for loop, going from record 2 (the first record with data) through record records-1, the last data record.


var record = dataRecords[i]Split(",");

We again use split (split is really convenient, as you have noticed!) to split the current row of data into an array of values. We store this array in the local variable record.


var curUser = User.lookup(record[0]);

OK. Now we are really getting into the meat of the function. We use the WCJS user object lookup method to return the object for the user specified in record[0] (the data that was in column 1 of your data file). If the user does not exist, a null value is returned instead. The returned value is stored in the local variable curUser.


+ '<P>';

Here we are just starting a new paragraph in the response page.


If (curUser == null) {
+ "User" + record[0] + " is not registered - Will automatically register. <BR>";
curUser = new User(record[0]);
}

We check the value of curUser to see if it is null (which it would be if the user does not already exist). If the user does not exist, an appropriate message is sent to the response page.

But we don't just leave it at that. If the user does not exist we just march right ahead and create the user!

To do this, we use the built-in WCJS User constructor function to create a new user object. As soon as this line is executed a new user with the name specified in record[0] is immediately added to the Web Crossing database. At this point, the new user has no password or email address set - just a userName and the usual default properties that all new users have.


+ "User " + record[0] + " is registered.<BR>";

After either registering the new user, or confirming that the user already exists, we output an appropriate message to the response page.


var confmsg = "User: " + record[0];

At this point we start building a confirmation message in the local variable confmsg. The confirmation message is output after all the properties for this user are set. This message will contain a list of all the properties set for this user and their values.


For (var j=1; j<nProperties; j++) {

Loops within loops! This for loop goes through the elements of record one-by-one extracting the property value and assigning the value to the property name specified in the corresponding propertiesList array element.


curUser[propertiesList[j]] = record[j];

Here we make the actual assignment of the value to the property. JavaScript associative arrays are used to specify the property name. That is, the value of properties[j] is the jth property name.

If the property already exists for this user, the value is overwritten with the new value. If the property does not exist, it is created.


confmsg += " " + propertiesList[j] + ": " + record[j];

Here we append the property name and value to the confirmation message.


}

This parenthesis closes the innermost for loop - the loop that sets the properties for the current user.


+ confmsg + "<BR>";

After we are finished with the current user, we append the confirmation message to the response page.


}

This parenthesis closes the outermost for loop - the "user loop."


+ 'Done<BR>';

After we are finished with the last user we append a "Done" message to the response page.


+ '<BODY></HTML>';
} %%

Finally we close the HTML tags for the response page and finish the function definition.

Where to Go from Here?

After you feel comfortable with the introduction in these sections on Web Crossing JavaScript, you will want to experiment with making your own functions. Your first point of reference should be the complete list of objects and properties in the online sysop reference manual.

The potential for using Web Crossing server-side JavaScript as a complete Internet applications builder is really limitless. We envision projects such as calendar systems sharing data between cooperating Web Crossing servers (using XML-RPC protocol to exchange information), the building of online, interactive, searchable database systems, online shopping systems, online auction systems, interactive educational systems and just about anything you can imagine creating for our increasingly wired planet.

Troubleshooting

When I tried setUserProperties it seemed to work for a few users, but after that the data seemed to get input in a different order than I expected.

When I tried this with 600 users, only the first 400 were read in, and then the function stopped. What can I do to read in large numbers of users?

Resources

Sysop docs:

Recommended book:

Developer Center