Due to the importance of a database in managing a membership-based community, starting with a careful design of the information to be collected proves invaluable in the subsequent development steps.
Establishing a New Account means implementing a New Account sign up process and recording the information necessary to track that New Member.
In developing a membership-based Web site, it is critical that you provide an efficient method to log a user onto the site and to validate a user's membership status.
To manage a membership-based site without incurring unreasonable administrative expenses, the site must provide facilities that enable users to maintain their own account information.
Building a membership-based community immediately demands certain features and functionality requirements that should be provided as part of the site. These features almost always require a database and generally include a New Account sign up process, logon/validation, and a series of account maintenance and administrative features.
You should begin the design process by assessing the membership database required for collecting the necessary membership information and for tracking user activity. The membership- related database tables will store user information for customizing the user's experience at the site, for evaluating current status and permissions, and for assessing appropriate billing. These critical features highlight the importance of properly design. The design decisions will ensure that the required fields of information are available and the performance requirements for the database are met.
![]()
Generally, membership means a database. Any other method of tracking membership-related information is unreasonably costly and inefficient.
Once a well-designed data structure has been established, the following sections detail the features necessary to manage the membership-based environment including the New Account sign up process, logon/validation features, and users account maintenance. Establishing a New Account sign up process provides a good starting point, as it often highlights required features that may have been overlooked in the initial design process. The logon and account validation code should have a focus on efficiency and security for the site. The logon and validation components primarily focus on controlling which aspects of the site users can reach, and they provide an important mechanism to ensure security and fee collection features of the site are properly enforced.
As you turn your development activities toward managing account status and history tracking, as well as account maintenance and administrative activities, your focus turns toward automating the administrative activities involved in account upkeep and reporting requirements.
The database design process for creating the Membership table provides a system for defining various types of information to be used by the system. Minimally, the information collected should include a unique ID to track the various members. In practice, additional information will be collected in several categories:
In the Love@1st Site Introduction Service (Service), we undertook a comprehensive design phase, involving the key constituencies involved in creating, financing, and using the site to determine the necessary information to track about the user community. The information includes system information, administrative information, e-mail services related flags, Member Profile data, and a profile of the member's Ideal Mate.
![]()
The table information illustrated as follows shows field information based on a Microsoft Access table; this maintains consistency with the presentation of this book and was the environment used during testing of the site. The production version of this site is Microsoft SQL Server.
From the system level, we determined a series of fields of information we had to collect to manage the member at the site. The specific fields of the Membership table, which can be found on the book's Web site are listed in Table B.1:
Table B.1 The Database Structure of the Primary System Information of the Membership Table
Field Name | Data Type | Size | Description |
MemberID | Number (Long) | 4 | Core account number-hidden from user |
SignOnID | Number (Long) | 4 | Session ID-temporary value for tracking |
Download | Number (Long) | 4 | Flag for downloading information to accounting system |
ReferredBy | Text | 25 | Information on accounts referred from partner Websites |
InactivateReason | Number (Long) | 4 | Reason flag for inactive status |
CompletedProcess | Yes/No | 1 | Flag to show successful completion of New Account sign up and billing process |
Some of fields utilized for system-related functionality are classified as Administrative fields to illustrate that they can be updated by site administrators through Active Server Pages. Together, System and Administrative fields form the set of information used by the system to manage members. System information is updated only by the core program itself and not by members or administrative users of the site.
Administrative information, like System information, provides key data for tracking and managing the member, the key distinction being that Administrative information can be edited by administrative users of the site. Allowing key membership-related information to be administered by site users is a fundamental method for distributing control and management tasks away from the code writer to the site users. This creates the mechanism for avoiding continual upgrades to code. The key administrative fields for the Membership table are listed in Table B.2.
![]()
The key value of editable information will be demonstrated in more depth in the administrative Appendix, as you note the parameter-driven nature of core features ranging from drop-down box options to billing structures.
Table B.2 The Database Structure of the Primary Administrative Information of the Membership Table
Field Name | Data Type | Size | Description |
AdmCreateDate | Date/Time | 8 | Initial account creation data |
AdmModDate | Date/Time | 8 | Date account last modified |
AdmStartDate | Date/Time | 8 | Date paid membership began |
AdmExpDate | Date/Time | 8 | Date valid membership status expired |
AdmOnlineDate | Date/Time | 8 | Date user last logged onto site |
AdmPublic | Yes/No | 1 | Flag denoting searchable account |
AdmStatus | Number (Long) | 4 | Status of member account, i.e. active, inactive |
Admingraphics | Yes/No | 1 | Graphic images submitted for display by member, a prerequisite for active account status |
The profile information displays information entered by the users themselves for other members to view. The profile information enables the searching features of the site and allows members to get to know each other while deciding whether or not to introduce themselves. The specific information includes all the fields illustrated in Table B.3.
Table B.3 The Database Structure of Profile and General Demographic Information of the Membership Table
Field Name | Data Type | Size | Description |
Pass | Text | 50 | Password for secure access |
FName | Text | 30 | First name |
LName | Text | 50 | Last name |
Address1 | Text | 150 | Address line one |
Address2 | Text | 150 | Address line two |
City | Text | 50 | City |
StateID | Text | 2 | State |
Zip | Text | 20 | Zip code |
HMPhone | Text | 30 | Home phone number |
HMAreaCode | Text | 3 | Home area code (for searching) |
WKPhone | Text | 30 | Work phone number |
WKAreaCode | Text | 3 | Work area code (for searching) |
PublicPhone | Number (Long) | 4 | Flag denoting phone number can be released |
Text | 50 | E-mail address | |
PublicEmail | Yes/No | 1 | Flag denoting e-mail address can be released |
Maiden | Text | 50 | Mother's maiden name for validation if password is lost |
ProfSex | Yes/No | 1 | Male or female |
ProfPrefID | Yes/No | 1 | Preferred sex (can not be altered) |
ProfRaceID | Number (Long) | 4 | Ethnic/racial background |
ProfRlgnID | Number (Long) | 4 | Religion |
Profdob | Date/Time | 8 | Date of birth for custom birthday notes and user validation |
ProfHeightF | Number (Long) | 4 | Member height (feet) |
ProfHeightI | Number (Long) | 4 | Member height (inches) |
ProfBodyID | Number (Long) | 4 | Member body type |
ProfStatusID | Text | 50 | Marital status (Married is not an option) |
ProfEdID | Number (Long) | 4 | Education level |
ProfOcc | Text | 150 | Occupation description |
ProfChldNum | Number (Long) | 4 | Number of children |
ProfChldExist | Number (Long) | 4 | Flag whether or not member has children |
ProfChldNew | Number (Long) | 4 | Interest in having children |
ProfSmkgID | Number (Long) | 4 | Smoking status |
ProfDrkgID | Number (Long) | 4 | Drinking status |
ProfEyeID | Text | 15 | Member's eye color |
ProfHairID | Text | 15 | Member's hair color |
ProfAct | Memo | - | Member general entry of activities they enjoy |
ProfMovie | Text | 100 | Favorite movies |
ProfMusic | Text | 50 | Multiple selection list for music IDs |
ProfBook | Text | 100 | Last book read |
ProfWhat | Memo | - | What are you looking for in a relationship question |
ProfQ1ID | Number (Long) | 4 | ID of second parameter-driven question |
ProfQ1Info | Memo | - | Answer to parameter-driven question |
This profile and demographic information is used to dynamically build profile pages for display to users interested in learning more about a certain member that they find in a search or who requests their introduction.
The Service provides extensive e-mail features for its membership community as a method of communication between members. Members may generate e-mails to other members through the system without the identity of either member being released. And based on profiles and flag selections, the system may automatically generate an e-mail message to notify a member of an introduction request or that someone matching her Ideal Mate profile has joined the membership community. The flags in the Membership table that manage this set of features are included in Table B.4.
Table B.4 The Database Structure of Automatic E-mail Services Flags in the Membership Table
Field Name | Data Type | Size | Description |
Eselect | Yes/No | 1 | Send me a message when another member selects me. |
Eaccept | Yes/No | 1 | Send me a message when a member I have selected accepts my request. |
EGenie | Yes/No | 1 | Send me a message if a member matching my Ideal Mate profile joins. |
EGen | Yes/No | 1 | Send me general site announcements of events. |
EOK | Yes/No | 1 | Allow members to send me notes after they have selected me. |
Microsoft SQL Server's "send mail stored" procedure drives these e-mail services that are executed through database calls by Active Server Pages through the ActiveX Data Object (ADO) component.
The Ideal Mate-related profile very closely mirrors the Member Profile information and enables a member to customize the search utilities to the profile that she will use most often when searching the system. In addition, the Ideal Mate profile provides a mechanism that enables the system to attempt matching New Members with members already in the system. This automated matching feature sends users e-mail notifications that encourage them to return to the site and provides them with value-added services to facilitate members finding members. The specific fields associated with managing these features are illustrated in Table B.5.
Table B.5 The Database Structure of Ideal Mate Profile Information in the Membership Table
Field Name | Data Type | Size | Description |
idlRaceID | Number (Long) | 4 | Ideal Mate race |
idlagehigh | Number (Long) | 4 | Ideal Mate age range (high) |
idlagelow | Number (Long) | 4 | Ideal Mate age range (low) |
idlRlgnID | Number (Long) | 4 | Ideal Mate religion |
idlHeightFlag | Number (Long) | 4 | Ideal Mate height above or below flag |
idlHeightF | Number (Long) | 4 | Ideal Mate height (feet) |
idlHeightI | Number (Long) | 4 | Ideal Mate height (inches) |
idlSmkgID | Number (Long) | 4 | Ideal Mate smoking status |
idlDrkgID | Number (Long) | 4 | Ideal Mate drinking status |
idllocflag | Yes/No | 1 | Ideal Mate location flag, i.e. is location relevant? |
idllocarea1 | Text | 3 | Ideal Mate area code if relevant |
idllocarea2 | Text | 3 | Ideal Mate area code, number two if relevant |
With the table design completed for the Membership table, developing a member sign up process becomes the first step of site creation. This enables the testing users to enter members and to work with the site almost immediately, leading to a clarification of missing information that has to be added to the site.. The New Account sign up process results in five separate Active Server Pages or .asp files. The initial development of the pages focused entirely on functionality, with graphic design and general look enhancement taking place at the very end of the development process.
The five-step New Account process walked the prospective member through the entering of Ideal Mate, Profile, demographic information, billing selection, and payment choices. Whereas the final two steps relating to billing are dealt with extensively in a later chapter, at this point we will explore the creation of a New Account.
The initial page shown in Figure B.1 largely presents standard HTML, providing information within a standard form that enables users to enter data and to select options. The only significant use of Active Server Pages features includes the lookup of parameters to populate drop-down lists and the server-side include of a validation .asp file, which will be explored in more detail later in this chapter. This page, however, initiates the session and collects the Ideal Mate information used to initially insert a New Member record in step 2.
The initial New Account Page collects beginning information prior to inserting a New Member record.
Listing B.1 illustrates the Server-Side Include feature and the defaulting of drop-down values for ethnic background.
Listing B.1 NEWACCT1.ASP-First Page in the New Account Sign up Process
<!--#include file="validatenew.asp"--> <% Set Conn = Server.CreateObject("ADODB.Connection") Conn.Open("firstsite") ' -------------------------------- ' -------------------------------- ' Output HTML Area ' -------------------------------- ' -------------------------------- %> ... <tr><td width=20%><font color="#0000A0"> Ethnic Background:</font></td><td width=50%> <select name="idlraceid" size=1 > <option checked value="0"><font color="#0000A0">No Preference</font></option> <% Set RS = Conn.Execute("SELECT * FROM AdminParameters where (systypeparam = 1)[ic:ccc] order by colatingorder;") Do While Not RS.EOF %> <option value="<%=rs("sysparamid")%>"><%=rs("paramvalue")%></option> <% RS.MoveNext Loop RS.Close %> </select></td></tr> ...
The code illustrated in Listing B.1 includes an example of how a parameter table can be used for populating options in the system. This parameter table can then be maintained by site administrators through standard Active Server Pages.
During step 2, shown in Figure B.2, the initial account record is created with the add new method. In addition to the Server-Side Include validation in step 1 and the parameter-driven populating of drop-down boxes illustrated in step 1, step 2 checks logon status to ensure that the current user has not already inserted the initial record; then step 2 either does an database insert or simply redisplays the account ID, depending on the logonstatus of the session ID. Listing B.2 illustrates the database insert and user validations done in step 2.
This is a sample of the form fields present in step 2 of the New Account sign up process.
Listing B.2 NEWACCT2.ASP-Inserting the Initial Record with Ideal Mate Information from Step 1 and System/Administrative Defaults for the New Account
<!--#include file="validatenew.asp"--> <% Set Conn = Server.CreateObject("ADODB.Connection") Conn.Open("firstsite") Select Case session("logonstatus") Case 3 ' Already Past this insert step msg = "<blink>Please Record your New Member ID:</blink> [ic:ccc]" & session("memberid") & " " Case 2 ' Proper Status for Insert of New Account set rsInsert = Server.CreateObject("ADO.RecordSet") 'Conn.BeginTrans rsInsert.Open "Members", Conn, 3, 3 rsInsert.AddNew rsInsert("SignOnID") = session.sessionid rsInsert("AdmCreateDate") = Date() rsInsert("AdmModDate") = Date() rsInsert("AdmStartDate") = Date() rsInsert("AdmOnlineDate") = Date() rsInsert("AdmPublic") = 0 rsInsert("AdmStatus") = 0 rsInsert("publicphone") = 0 'Testing Uncertain Values heightF = request.form("idlHeightF") heightI = request.form("idlHeightI") if heightF = "" then heightF = 0 if heighti = "" then heightI = 0 rsInsert("idlRaceID") = request.form("idlRaceID") rsInsert("idlAgeHigh") = request.form("idlAgeHigh") rsInsert("idlAgeLow") = request.form("idlAgeLow") rsInsert("idlRlgnID") = request.form("idlRlgnID") rsInsert("idlHeightFlag") = request.form("idlHeightFlag") rsInsert("idlHeightF") = heightf rsInsert("idlHeightI") = heighti rsInsert("idlSmkgID") = request.form("idlSmkgID") rsInsert("idlDrkgID") = request.form("idlDrkgID") rsInsert("idlLocFlag") = request.form("idllocflag") rsInsert("idlLocArea1") = request.form("idllocarea1") rsInsert("idlLocArea2") = request.form("idllocarea2") rsInsert("download") = 0 rsInsert("stateid") = "CA" rsInsert.Update 'Conn.CommitTrans rsInsert.Close sql = "SELECT Members.SignOnID, Members.memberid, Members.AdmCreateDate FROM Members WHERE[ic:ccc] (((Members.SignOnID)=" & session.sessionid & ") AND ((Members.AdmCreateDate)=Date()));" Set RS = Conn.Execute(sql) msg = "<blink>Please Record your New Member ID:</blink> " & rs("memberid") & " " ' --------------------------------------- ' Set Session Object with memberid value ' --------------------------------------- memval = rs("memberid") session("memberid") = memval session("logonstatus") = 3 rs.close End Select ' -------------------------------- ' -------------------------------- ' Output HTML Area ' -------------------------------- ' -------------------------------- %> ...
Step 3 (see Figure B.3) provides an update SQL statement to add additional profile information to the New Members record. To update the record, step 3 performs a series of data evaluations and manipulations to prepare the information for the update statement. Conditional processing such as If/Then statements and For/Next loops are used to evaluate form-based information, and in addition to simple evaluations, a callable string function is invoked for modifying various fields to strip out single and double quotation marks, which can affect the SQL-based update statement.
Step 3 of the New Account process updates the newly inserted record with the additional profile information entered in step 2.
The code in Listing B.3 illustrates several important features associated with the update of an existing account. In addition to the update of the account record in the database, Listing B.3 also illustrates callable functions and variable testing.
Listing B.3 NEWACCT3.ASP-The Use of a Callable Function, Variable Testing, and Update SQL Statement
<!--#include file="validatenew.asp"--> <script language=vbscript runat=server> Function StripChars(txtstring) tempstring = "" length = Len(txtstring) For i = 1 To length singlechar = Mid(txtstring, i, 1) If singlechar = Chr(34) then tempstring = tempstring & Chr(180) & Chr(180) ElseIf singlechar = Chr(39) then tempstring = tempstring & Chr(180) Else tempstring = tempstring & singlechar End If Next StripChars = tempstring End Function </script> <% Set Conn = Server.CreateObject("ADODB.Connection") Conn.Open("firstsite") 'Set Conn = Session("Conn") ' ------------------------------------------- ' Update based on member id in session object ' ------------------------------------------- 'Testing Uncertain Values '-------------------------- OCC = request.form("profocc") act = request.form("profact") movie = request.form("profmovie") music = request.form("profmusic") book = request.form("profbook") what = request.form("profwhat") Q1Info = request.form("profQ1Info") heightF = request.form("profHeightF") heightI = request.form("profHeightI") dob = request.form("profdob") profhairid = request.form("profhairid") profeyeid = request.form("profeyeid") if occ = "" then occ = "NA" if act = "" then act = "NA" if movie = "" then movie = "NA" if music = "" then music = 0 if book = "" then book = "NA" if what = "" then what = "NA" if Q1info = "" then Q1info = "NA" if HeightF = "" then HeightF = 0 if Heighti = "" then HeightI = 0 if dob = "" then dob = "01/01/01" '------------------------ if request.form("profsex") <> "" then sql = "UPDATE Members SET" sql = sql & " Members.ProfSex =" & request.form("profsex") & "," sql = sql & " Members.ProfPrefID =" & request.form("ProfPrefID") & "," sql = sql & " Members.ProfRaceID =" & request.form("profRaceID") & "," sql = sql & " Members.ProfRlgnID =" & request.form("profRlgnID") & "," sql = sql & " Members.Profdob =#" & stripchars(dob) & "#," sql = sql & " Members.ProfHeightF =" & stripchars(HeightF) & "," sql = sql & " Members.ProfHeightI =" & stripchars(HeightI) & "," sql = sql & " Members.ProfBodyID =" & request.form("profBodyID") & "," sql = sql & " Members.ProfStatusID ='" & request.form("profStatusID") & "'," sql = sql & " Members.ProfEdID =" & request.form("profEdID") & "," sql = sql & " Members.ProfOcc ='" & stripchars(occ) & "'," sql = sql & " Members.ProfChldNum =" & request.form("ProfChldNum") & "," sql = sql & " Members.ProfChldExist =1," '& request.form("ProfChldExist") & "," sql = sql & " Members.ProfChldNew =1," '& request.form("ProfChldNew") & "," sql = sql & " Members.ProfSmkgID =" & request.form("ProfSmkgID") & "," sql = sql & " Members.ProfDrkgID =" & request.form("ProfDrkgID") & "," sql = sql & " Members.ProfEyeID ='" & ProfEyeID & "'," sql = sql & " Members.ProfHairID ='" & ProfHairID & "'," sql = sql & " Members.ProfAct ='" & stripchars(act) & "'," sql = sql & " Members.ProfMovie ='" & stripchars(movie) & "'," sql = sql & " Members.ProfMusic ='" & stripchars(music) & "'," sql = sql & " Members.ProfBook ='" & stripchars(book) & "'," sql = sql & " Members.ProfWhat ='" & stripchars(what) & "'," sql = sql & " Members.ProfQ1ID =" & request.form("ProfQ1ID") & "," sql = sql & " Members.ProfQ1Info ='" & stripchars(Q1Info) & "' " sql = sql & " WHERE (((Members.AdmCreateDate)=Date()) AND" sql = sql & " ((Members.memberID)=" & session("memberid") & "))" Set rsupdate = Server.CreateObject("ADO.Recordset") rsupdate.Open sql, Conn, 3 end if Set rsStates = Conn.Execute("SELECT StatePostalCode FROM States;") ' -------------------------------- ' -------------------------------- sql = "SELECT * FROM Members WHERE MemberID=" & session("MemberID") & ";" Set rs = Conn.Execute(sql) %>
The New Account Sign Up process involves the creation of a New Account record; a prospective member's data is carefully entered into the database, tracked, and evaluated for potential matches as the prospective member moves through a series of screens that guides the entry of information. Some of the key Active Server features invoked include:
Once a New Member Profile has been successfully created and activated by whatever administrative process has been created, a logon process must be created to validate a user's identity. In addition, with a membership paradigm, users who attempt to open an .asp file without logging on must be trapped and routed to a logon screen for validation. At first glance, this process seems to require the use of Windows NT Server's User Manager. After a quick review, however, it becomes clear that managing the authentication process through a database has many benefits over the user manager from maintainability and efficiency perspectives. As a result, I leave the user manager for highly sensitive security issues such as site administration and immediately rely on database lookups for membership authentication.
The components of an effective Logon and Validation model include a logon screen, which can set a session variable for tracking the logon status, and a validation .asp file, which is included at the top of every page and which redirects users to the logon screen if they do not pass a simple check of the logon session variable. These components immediately provide much better security than most solutions found on the Web today. One of the benefits of a session variable is that it only resides at the server. Rather than writing a status with a cookie, which can be "spoofed", the logon status relates to a given Session ID on the browser and, therefore, does not get directly passed over the Internet.
![]()
Generally, on the Internet, spoofing refers to creating a transaction where the one computer pretends to the have the address, or identity, of another computer. We use this imagery because with a faked cookie, a computer could send a transaction to the Web server that would lead it to mistakenly assume it was a different computer.
The logon process can be more or less complicated, depending on your method for authenticating the member. The logon screens should also be candidates for two types of security measures. First, the field in which a password or other type of information is entered should be set as a password so that asterisks are displays in the browser in place of the data entered by the user; second, this screen may also be used with an SSL socket (i.e. HTTPS:// reference) to ensure the encryption of password information as it passes over the network. These security decisions depend on the level of security required at your site.
![]()
Secure Sockets Layer (SSL) SSL provides the most widely used mechanism for securing Web-related information in transit on the Internet. In summary, SSL provides an encryption standard for Web browsers and Web Servers to securely share information.
The initial logon page simply requires a form field for the entry of whatever validation information needs to be submitted. For our Introduction Service, Figure B.4 displays the logon screen and all required information captured, including the MemberID and a Password.
This is the Logon Entry Screen used to submit member ID and password information.
In addition to the basic data entry fields, our Service displays a system message that explains why the user ended up at this page. The appropriate message string is set to a Session property and subsequently displayed if a failed logon attempt occurs or if the user gets routed to the logon screen from a validation in some other .asp file. In addition, if the Session property used for storing messages is left empty, then the current session is abandoned to enable the user to log on again. Listing B.4 illustrates the code used at the top of the .asp file to check the Session property containing the message and either display the message, if the logon attempt failed, or abandon the current Session and allow a new logon to occur.
Listing B.4 LOGON.ASP-Illustration of Message Display at the Top of the Logon Page
<% msg = session("msg") '--------------------------------------' Output HTML Section '-------------------------------------- %> <html><head><title> Love@1st Site - Interactive Introductions-Logon </title></head><body bgcolor="#FFFFFF"> <%=msg%> <% If session("msg") = "" then session.abandon End If session("msg") = "" %>
Once the initial logon request is submitted, the Service begins a comprehensive set of evaluation routines to identify whether or not the logon attempt authenticates the user, and if not, to determine why the authentication attempt failed.
The logon.asp invokes the logoncheck.asp file, which directly outputs nothing. The authentication file simply evaluates the logon attempt and either redirects a successful logon to the start.asp page or sets a message to the session (msg) variable and redirects the user back to the logon.asp page. If a successful logon occurs, the logoncheck.asp also writes an update back to the Membership table to change to the current date/time, the date/time field used for tracking the last time the user logged on to the Service.
The code illustrated in Listing B.5 shows the process for authenticating the user on the Service. The code also handles the different failure conditions that can result by carefully reviewing all possible failures followed by a comprehensive message back to the user.
![]()
The logoncheck.asp cannot directly write HTML output because the redirect feature does not function once HTTP headers have been sent (see format of HTTP record for more details about what the headers include). Headers are sent as soon as a response.write event occurs.
Listing B.5 LOGONCHECK.ASP-Authentication Process for Logon
<Script Language=VBScript runat=server> Function redirect() Response.Redirect "logon.asp" end function </script> <% Set Conn = Server.CreateObject("ADO.Connection") Conn.Open("firstsite") '----------------------------------------------------- '----------------------------------------------------- 'Level 1 Basic Validation Testing '----------------------------------------------------- '----------------------------------------------------- 'Test for Entry of Member ID prior to Running Search '----------------------------------------------------- if request.form("memberid")="" then ' No Member ID Entered session("msg") = "<h3><center>Oops! The Member ID# didn't work. Try the Member ID# search below.</center></h3>" Redirect 'Call Function to Exit Back to Logon Screen 'Run Search '----------------------------------------------------- else 'Run Database Lookup sql = "SELECT members.admonlinedate, Members.MemberID, members.pass, Members.FName, Members.LName, Members.AdmExpDate, Members.AdmStatus, Members.InactivateReason, Members.AdminGraphics, Members.AdmCreateDate FROM Members " sql = sql & "WHERE (((Members.MemberID)=" & request.form("memberid") & "));" set rs = conn.execute(sql) end if '------------------------------------------ '------------------------------------------ 'Level 2 Validation Testing '------------------------------------------ '------------------------------------------ If not rs.eof then test = rs("memberid") session("memberid") = test End If 'Member ID Entered Now Run Search for Record '------------------------------------------- If rs.eof Then 'No Record Found Bad ID rs.close session("msg") = "<h3><center>Oops! We couldn't find Member ID# <em>" & request.form("memberid") & "</em>. Please try again or use our Member ID# [ic:ccc]Search below.</center></h3>" Redirect 'Call Function to Exit Back to Logon Screen 'Customer Record Found Now Check Password '----------------------------------------- elseif not request.form("password") = rs("pass") then rs.close session("msg") = "<h3><center>Oops! Your ID# is okay, but the password didn't work. (Remember it is case sensitive) Try again.</center></h3>" Redirect 'Call Function to Exit Back to Logon Screen 'Check for inactive status '------------------------------------------- elseif rs("admstatus") = 0 then if rs("CompletedProcess") = 0 then rs.close session("msg") = "<h3><center>Not Active or Expired Account</center></h3>" Redirect 'Call Function to Exit Back to Logon Screen end if 'Password OK now check to see if pictures arrived. They have 30 days. '--------------------------------------------------------------------- elseif (rs("admingraphics") = 0) and (rs("admcreatedate") + 30 < date()) then session("msg") = "<center><font color=" & """" & "#FF0000" & """" & ">[ic:ccc]<strong>We have not received your photos yet. You are not able to access Member Services until we receive your photos.</strong></font></center>" session("scanaction") = "lockout" Response.Redirect "scan.asp" 'See if pictures arrived. After 15 days they get a warning message. '--------------------------------------------------------------------- elseif (rs("admingraphics") = 0) and (rs("admcreatedate") + 15 < date()) then session("msg") = "<center><font color=" & """" & "#FF0000" & """" & "><strong>[ic:ccc]We have not received your photos yet. If we do not receive your photos prior to " & rs("admcreatedate") + 15 & ", we will remove your access to Member Services.</strong></font></center>" session("scanaction") = "warning" Response.Redirect "scan.asp" '----------------------------------------------------- '----------------------------------------------------- ' Step 3. Success Logon Approved '----------------------------------------------------- '----------------------------------------------------- else session("logonstatus") = 1 session("AdmOnlineDate") = rs("AdmOnlineDate") sql = "UPDATE Members SET" sql = sql & " Members.AdmOnlineDate = #" & Date() & "#" sql = sql & " WHERE Members.MemberID=" & request.form("memberid") & ";" set rs2 = conn.execute(sql) response.redirect "start.asp" end if rs.close %>
Two discrete validation .asps are used in the Service. The first validate.asp file is used in every page with the exception of the New Account pages, while the second validatenew.asp is used on all New Account pages. Both validation pages rely on the Session property named logonstatus.
The New Account validation pages uses the logon status Session property extensively to monitor what point in the New Account process New Members have reached. This file relies on the select case statement to evaluate all possible statuses of the logon status Session property. Currently only Case 0 and 1 are in use. Listing B.6 illustrates the code of the Select Case statement used to evaluate the Logon Status on New Account Pages
Listing B.6 VALIDATENEW.ASP-The Select Case Evaluation of the Logon Status Variable for Users in the New Account Pages
<% 'Set ADO Object variable for use in remainder of page processing Set Conn = Server.CreateObject("ADODB.Connection") Conn.Open("firstsite") Select Case session("logonstatus") Case 0 'New Session No Status session("logonstatus") = 2 Case 1 session("logonstatus") = 2 Case 2 'New Member in Sign Up Process first page Case 3 'New Member in Sign Up Process Record Created Case 4 'New Member in Sign Up Process Error Status End Select %>
The standard validate.asp file, which is invoked with a Server-Side Include statement on all other pages, provides evaluations very similar to the validatenew.asp file, with one minor exception: It only takes action if a logon status is 0. Every other status qualifies either as a New Member in process or as a properly logged on member account. The code for this evaluation is illustrated in Listing B.7.
Listing B.7 VALIDATE.ASP-Validation File Included in All .asp Files Other than the New Account Pages
<% Set Conn = Server.CreateObject("ADODB.Connection") Conn.Open("firstsite") Select Case session("logonstatus") Case 0 'New Session No Status session("msg") = "<h3><center> Your are currently not logged in or your [ic:ccc]login has timed out </center></h3> Please logon to continue your session, sorry for any inconvenience</h4>" Response.Redirect "logon.asp" Case 1 'Authenticated User Properly Logged On Case 2 'New Member in Sign Up Process first page Case 3 'New Member in Sign Up Process Record Created End Select %>
The Logon and Validation process requires a small amount of code and only a couple of .asp files, but based on Server-Side Includes, these files find their way into every single Active Server Page processed for delivery to the client. Although not complex in implementation, this file provides the heart of membership security features and should be carefully put into effect. Some of the key Active Server features invoked include:
Implementing a cost-effective, fee-based subscription service requires automating the costly administrative responsibilities that can develop due in part to member account maintenance and site enhancement. As one effective step in controlling these costs and at the same time empowering the user community with additional control and convenience, a site should place as much maintenance responsibility as possible with the end user community. The Introduction Service places extensive maintenance features in the hands of the members, as illustrated on the primary maintenance screen in Figure B.5. From Ideal Mate settings to billing information, the member has control.
This is the primary maintenance screen for a member to administer his account information.
Enabling members to edit these pages simply involves taking the New Account pages and adapting them for update. The primary change involves defaulting all values in the form fields to be populated with a member's currently set information. In addition, these pages will be updated out of order rather than linearly as with the New Account process. Without going into repetitive detail with the editacctX.asp files, in Listing B.8 I will illustrate just the editacct3.asp, which contains Member Information. The key task involves looking up the customer record and ensuring that the member ID of the currently logged on user matches the one used to look up customer information so that no other user can accidentally edit another member's account.
Listing B.8 EDITACCT3.ASP-Member Editing of Account Information Based on Defaulted Form Field Values
<% Set Conn = Server.CreateObject("ADODB.Connection") Conn.Open("firstsite") sql = "SELECT * FROM Members WHERE MemberID=" & session("MemberID") & ";" Set rs = Conn.Execute(sql) Set rsStates = Conn.Execute("SELECT StatePostalCode FROM States;") 'Testing Uncertain Values '-------------------------- OCC = request.form("profocc") act = request.form("profact") movie = request.form("profmovie") book = request.form("profbook") what = request.form("profwhat") Q1Info = request.form("profQ1Info") heightF = request.form("profHeightF") heightI = request.form("profHeightI") dob = request.form("profdob") if occ = "" then occ = "NA" if act = "" then act = "NA" if movie = "" then movie = "NA" if book = "" then book = "NA" if what = "" then what = "NA" if Q1info = "" then Q1info = "NA" if HeightF = "" then HeightF = 0 if Heighti = "" then HeightI = 0 if dob = "" then dob = "01/01/01" %> <html> <base href="http://www.1st-site.com/"> <head> <title>Edit Membership Information</title> </head> <form action="editacctupdate.asp" target="_top" method="POST"> <body bgcolor="#FFFFFF" text="#0000A0"> <table border=1 cellpadding=8 cellspacing=0 width=604> <tr><td> <p>Changed your home or e-mail address? Want to change your password? Care to change your e-mail notification preferences? Modify your information and preferences below, then click on the Update button. Your changes will take effect immediately. </p> </td> </tr> <tr> <td align="center"> <br> <br> <table width=100%> <tr><td width=30% valign="top">Password:</td><td colspan=2 width=40% valign="top"><input type=password size=10 maxlength=10 name="pass" value="<%=rs("pass")%>"></td></tr> ...
All edit files invoke the one editaccountupdate.asp file illustrated in Listing B.9. This file centralizes all of the update statements into one file to isolate the code associated with updating accounts. This process of organizing .asp files in an intuitive manner for managing your code can provide invaluable support when you need to edit your code. The editaccountupdate.asp simply executes an update sql statement based on the fields entered.
Listing B.9 EDITACCOUNTUPDATE.ASP-Centralized .asp for Updating Member Accounts Based on Member-Intiated Updates of their Member Information
... sql = "UPDATE Members SET" if request.form("fname") <> "" then sql = sql & " Members.fname ='" & stripchars(request.form("fname")) & "'," end if if request.form("lname") <> "" then sql = sql & " Members.lname ='" & stripchars(request.form("lname")) & "'," end if sql = sql & " Members.pass ='" & stripchars(pass) & "'," sql = sql & " Members.address1 ='" & stripchars(address1) & "'," sql = sql & " Members.address2 ='" & stripchars(address2) & "'," sql = sql & " Members.city ='" & stripchars(city) & "'," sql = sql & " Members.stateid ='" & request.form("stateid") & "'," sql = sql & " Members.zip ='" & stripchars(zip) & "'," sql = sql & " Members.hmareacode ='" & stripchars(hmareacode) & "'," sql = sql & " Members.hmphone ='" & stripchars(hmphone) & "'," sql = sql & " Members.wkareacode ='" & stripchars(wkareacode) & "'," sql = sql & " Members.wkphone ='" & stripchars(wkphone) & "'," sql = sql & " Members.publicphone =" & request.form("publicphone") & "," if request.form("email") <> "" then sql = sql & " Members.email ='" & stripchars(request.form("email")) & "'," end if sql = sql & " Members.publicemail =" & request.form("publicemail") & "," sql = sql & " Members.maiden ='" & stripchars(maiden) & "'," sql = sql & " Members.ESelect =" & request.form("eselect") & "," sql = sql & " Members.Eaccept =" & request.form("eaccept") & "," sql = sql & " Members.EGenie =" & request.form("egenie") & "," sql = sql & " Members.EGen =" & request.form("egen") & "," sql = sql & " Members.download = 1," sql = sql & " Members.AdmModDate = #" & Date() & "#," sql = sql & " Members.EOK =" & request.form("eok") & " " sql = sql & " WHERE Members.memberID=" & session("memberid") & ";" Set rs = Server.CreateObject("ADO.Recordset") rs.Open sql,Conn,3 End If newpage = "profile.asp?memberid=" & session("memberid") response.redirect newpage %>
The process of managing account information follows the pages utilized for creating a New Account very closely. Although these pages can be fairly easily copied over and modified for use, I recommend that you leave these edit account pages until late in the development process because changes in the New Account pages and Member table have cascading impact on the Edit Account Pages. Most test users have little need to manage accounts and can easily live without this set of features until late in the development process.
Establishing a membership-based community relies upon effective management of the New Account process, logon and account validation, and effective distribution of account maintenance into the membership community. However, if the community sponsor intends to charge fees for products and services, providing a compelling and interactive user experience coupled with effective administration and a convenient billing/payment service will determine the overall effectiveness of the site as a business venture.
Appendix C, "Delivering an Interactive Introduction Service," explores delivering an interactive service, followed by a look at the administrative and payment services included the Introduction Service site.
© 1997, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.