logo

Edit Profile Documents in Web Browser

Profile Documents in the browser. Can't be done right? Well, I think I might have found a simple way round it using the combination of a simple WQO and WQS agent.

I have a Notes client database that needs converting to the web. One of the tasks is to find a way to still allow users to edit their profile documents. At first I thought it wasn't possible, then I had a thought. Why can't I open the actual Profile Form and then use a WQO agent to copy all the fields over. When the user submits the form it simply copies all the fields back to the profile and saves it.

Let's say we have a profile based on a Form called "UserSettings". It's opened in the Notes Client in the usual way. Now, in the browser I suggest using a URL like:

http://server/db.nsf/UserSettings?OpenForm

This form has a WQO agent ("Run as Web User" enabled). The important code for which is:

Set vProfileDoc = vThisDB.GetProfileDocument("UserSettings",
vWebSess.EffectiveUserName)
Call vProfileDoc.CopyAllItems(vThisDoc, True)

Simple, no? Just copy all the item values over! Because it's the same form, in effect, all the fields are laid out as expected and it looks like the normal profile document.

To save the profile we need to add a WQS agent ("Run as Web User" enabled). The basic code for this is similar to the above (we still need to get a handle on the Profile) but looks like this:

Call vThisDoc.CopyAllItems(vProfileDoc, True)
Call vProfileDoc.Save(True, True)

Notice the CopyAllItems method has its document parameters switched. Notice also that we save the Profile document. This is important and something I forgot when I first tested the theory. Doh!

Another thing we need to do is add a SaveOptions field the Profile form. Because we're opening it like a normal form in the browser we don't want it to save. So, make the field hidden and computed then add a formula like this:

@If(@ClientType="Web"; "0"; "1")

I've done some crude testing and it all appears to work. Have I missed some detail that means it won't in reality? What normally happens is I find something like this and think "Must blog that right away!". What I should probably do is sit on it for a while and see how stable it is. This saves me looking like a fool if it isn't. Oh well, what the hell.

What struck me is that it's such a simple solution. I'm surprised I've not seen it described elsewhere. Has this been done before? If not, should I write a more detailed explanation/article and knock together a demo db for download?

Comments

    • avatar
    • Arka Nada
    • Fri 4 Nov 2005 04:54 AM

    I've been doing it the way you describe for (.. thinks ...) the last four or five years.

    Rather than copying across all the items, I usually have some definition of which items will be saved (the rest are discarded). This is useful when you have working or display fields that you dont' want to save on the backend document.

    This is actually a first stage in a "pattern" I use a lot, which is to decouple the form from the document. Usually, the form has a significant bearing upon what is stored in the document. If you decouple them, it doesn't.

    You can do this with normal documents as well as profile documents.

    • avatar
    • Jake Howlett
    • Fri 4 Nov 2005 04:55 AM

    I just found a problem though - cacheing. Is there any way round the fact that Domino caches profiles documents?

  1. Jake, you'll have to add a hidden field on your profile doc which stores the unid of the doc.

    Then refer to it in your code like

    unid := @GetProfileField("ProfileDoc"; "unid")

    and do eg

    myfield := @GetDocField(unid; "YourField")

    Caching does not matter anymore since this method gets and sets the values of the Notes profile document.

    HTH

  2. Jake

    I hate profile documents! I have had so uch trouble with them apparently updating but then when readback, the old values coming up that I have given up on them.

    I know it's something to do with cacheing, but I refuse to spend my time fighting Notes!

  3. As soon as I read the headline of this entry, I thought "Jake found a clean way around the caching?! SWEET!".

    You could always issue a 'dbcache flush' command from your WSQ agent? ;-)

    In truth, this is why I tend to not use profiles in my web-based or hybrid apps but rather documents.

    Hopefully someone out there's got a more solid solution than dropping cache just so a single databases profile changes can be seen from the web instantly!

    -Chris

  4. It's the http server task that caches the profile documents. An easy way to "refresh" the cache is to restart http... But I guess Chris' has right when saying that 'dbcache flush' works!

    • avatar
    • YoGi
    • Fri 4 Nov 2005 06:23 AM

    i've given up with profile documents on the web too. Too much caching problems. But Patrick's tip looks great, have to test it !

    • avatar
    • Fredrik
    • Fri 4 Nov 2005 07:03 AM

    I use a similar method, but instead of copying all fields I replace all fields with a specific prefix (CFG_"fieldname")

    The wqs-agent creates the profile and updates the profile. The form is just a GUI to modify the values (saveoptions = 0). The default value of each field in the gui is val:= @GetProfileField("MyProfile"; @ThisName). I also include a errorcheck (@if(@iserror(val)...) for each field so I can use a default value for each field if the profile or field doesnt exist.

    This will force the GUI to display the latest values from the profile.

    ...but I have the same problem as you Jake, the values are cached for the session. A workaround that sometimes works is to always delete the profile before updating it... but it might give you other problems (in a replicating environment).

    The soluton isn't perfect so I use it only for configuration settings etc (semi-static values)

    • avatar
    • Glen Holmes
    • Fri 4 Nov 2005 07:46 AM

    I've been doing this in an application I'm working on for a while. I have a profile form named Keyword_profile_frm. Instead of opening the profile form I open another form That I use to populate my Keywords, I have two fields on this form the "Key" field and the "KeyWordList" fields. I have a WQO and WQS agent on this form. The WQO acts the same as you've (Jake) has outlined. The only difference being that I use the CopyItem and ReplaceItemValue methods and I never have any caching issues!

    e.g. (from WQS agent)

    Set docProfile = curdb.GetProfileDocument ("Keyword_profile_frm")

    keyname = currentPage.GetItemValue("key")(0)

    Set keywordlist = currentPage.GetFirstItem("keywords")

    Dim keyValue As NotesItem

    Set keyValue = docProfile.GetFirstItem(keyname)

    If keyValue Is Nothing Then

    Call docProfile.CopyItem(keywordlist, keyname)

    Set keyValue = docProfile.ReplaceItemValue(keyname,keywordlist)

    Else

    Call docProfile.CopyItem(keywordlist, keyname)

    End If

    Call docProfile.Save(True,False)

    In saying that this is just used to update one profile doc with a set of key values but I can't see why i'm having no caching issues!

    • avatar
    • Glen Holmes
    • Fri 4 Nov 2005 07:56 AM

    Actually i'm looking at that code and can't remember why I was doing the ReplaceItemValue bit! (it was 4 years ago!) hmm... may just be working by fluke;-)

    • avatar
    • Jake Howlett
    • Fri 4 Nov 2005 08:01 AM

    Glen. Maybe cache behaviour is different if it's one main profile rather than a user-based profile?

    • avatar
    • Glen Holmes
    • Fri 4 Nov 2005 08:05 AM

    hmm.. maybe but i cant see why. I know i've used the method on a user-based profile before and i don't remember having any issues. I still have issues with caching in the client but never on the web!

    • avatar
    • ursus
    • Fri 4 Nov 2005 09:08 AM

    Hi Jake

    I can only assume that this is for my application. Should caching be a problem we can swap to normal Notes documents to store the settings - don't waste any of your time "fixing" the caching problem.

    I don't mind dumping the profile docs in the Notes client one little bit ;o)

    • avatar
    • Jake Howlett
    • Fri 4 Nov 2005 09:15 AM

    Now you tell me ursus ;o)

    • avatar
    • Dave
    • Fri 4 Nov 2005 10:07 AM

    wow! Jake just used his blog to change the requirements of a customer. Brilliant! :-)

    • avatar
    • John
    • Fri 4 Nov 2005 11:16 AM

    Dumping the profiles is the best solution. I played with user profiles enough to learn not to use them. Sounds like everything worked itself out.

    • avatar
    • Indy
    • Fri 4 Nov 2005 03:41 PM

    Watch out changing profile docs heavily, before you know it you've got multiple profile docs for 1 user! I've have seen mailboxes containing 5 profiledocs where there only shoud be 1!!

    Dim ses As New notessession

    Dim dbCur As notesdatabase

    Dim docProf As notesdocument

    Dim colProfs As notesdocumentcollection

    Dim strForm As String

    Dim n As Integer

    Set dbCur = ses.currentDatabase

    Set colProfs = dbCur.getprofiledocCollection

    Set docProf = colProfs.getFirstDocument

    n=0

    While Not docProf Is Nothing

    strForm = docProf.getItemValue("Form")(0)

    Set docProf = colProfs.getNextDocument(docProf)

    n=n+1

    Print "profile doc: " + Cstr(n)

    Wend

  5. I use a web agent to open the profile doc.

    Ex. /xx.nsf/WAGetProfile?OpenAgent&Name=ProfileDocName

    the code for WAGetProfile

    Sub Initialize

    On Error Goto ERRORHANDLER

    Dim session As New NotesSession

    Dim db As NotesDatabase

    Dim docCntxt As NotesDocument

    Dim docProfile As NotesDocument

    Dim sName As String

    Dim sUNID As String

    Dim sDBURL As String

    Set db = session.CurrentDatabase

    sDBURL = db.FilePath

    sDBURL = Replace(sDBURL, "\", "/")

    sDBURL = Replace(sDBURL, " ", "%20")

    Set docCntxt = session.DocumentContext

    sName = subUrlQueryString(docCntxt.Query_String(0), "Name" )

    If sName = "" Then

    Print |Error in Agent: | & session.CurrentAgent.name & |<br>| & docCntxt.Query_String(0) & |<br>| & |<a href="javascript: onClick=history.back()">Back</a>|

    Exit Sub

    End If

    Set docProfile = db.GetProfileDocument(sName)

    If docProfile Is Nothing Then

    Print |Error in Agent: | & session.CurrentAgent.name & |<br>| & docCntxt.Query_String(0) & |<br>| & |<a href="javascript: onClick=history.back()">Back</a>|

    Exit Sub

    End If

    docProfile.LOG = "1"

    docProfile.FORM = sName

    Call docProfile.Save(True, True)

    sUNID = docProfile.UniversalID

    Print |<html><head><script>document.location='/| & sDBURL & |/0/| & sUNID & |?OpenDocument'| & |;</script></head></html>|

    Exit Sub

    ERRORHANDLER:

    Print |Error in Agent: | & session.CurrentAgent.name & |<br>| & |Ln: | & Str$(Erl) & | Err: | & Str$(Err) & | | & Error$ & |<br>| & |<br>| & |<a href="javascript: onClick=history.back()">Back</a>|

    Err = 0

    Exit Sub

    End Sub

    • avatar
    • Fritz
    • Mon 7 Nov 2005 05:18 AM

    Has anybody thought about Profile-Docs's and Replication? We got three Webserver used for load balancing in our DMZ, another used as Replication-Hub and another Notes-Cluster is serving our Intranet.

    When you change a Profile-Doc on one Server, the others don't recognize them till http-restart. The http-Task will cache the Profiles on every Server. There is no issue as long as the user is only on one server.

    We simply don't use Profile-Documents on Web-Applications any more.

  6. It seems like folks love to hate the profile docs. Jake got the response he was hoping for ;-) But in my opinion profile docs are sometimes quite nice if used where appropriate and you know how they work.

    I don't experience problems with caching of profile documents. - Probably because I have used them in a single client-type and single author situation only. It's when you start mixing either of these or updates on several servers concurrently you may get into trouble.

    Although caching occurs in the front ends (notes client session and Http web server task), profile docs can be quite safely manipulated with backend lotusscript.

    I have a simple db that I used for learning, demonstration and monitoring how updating and caching works for profile docs. (You can mail me for a copy.)

Your Comments

Name:
E-mail:
(optional)
Website:
(optional)
Comment:


About This Page

Written by Jake Howlett on Fri 4 Nov 2005

Share This Page

# ( ) '

Comments

The most recent comments added:

Skip to the comments or add your own.

You can subscribe to an individual RSS feed of comments on this entry.

Let's Get Social


About This Website

CodeStore is all about web development. Concentrating on Lotus Domino, ASP.NET, Flex, SharePoint and all things internet.

Your host is Jake Howlett who runs his own web development company called Rockall Design and is always on the lookout for new and interesting work to do.

You can find me on Twitter and on Linked In.

Read more about this site »

More Content