XPages “Change document mode” not working (and why)

I just tried to add a “Change Document Mode” action on an XPage to be able to switch between read- and edit mode. The XPage (containing the document) opened fine in read mode, but after clicking the “Edit”  button, nothing happened. At first I thought it was trying to put the wrong data source in edit mode or that it had something to do with using multiple custom controls. A simple test with a new Xpage showed that this wasn’t the case. I then tried other things: changing the view control that showed all documents to open the document directly in edit mode, adding an ?action=editDocument parameter to the URL: all with no success.

Then it occurred to me: is the user allowed to edit the document at all? He wasn’t… Back in the days the Domino server used to tell you “you’re not allowed to perform that operation”, but that doesn’t seem to happen anymore: the document just stays in read mode.

The solution was to show the “edit” button only if the user is actually allowed to edit the document. To do that I wrote a function for the Visible property of the “edit” button that checks if the user is allowed to edit a document and hides it if he isn’t:

  • It first checks the access level to the parent database: editors or higher are allowed to edit, readers or lower are not.
  • If the user is an author it checks a field called docAuthors (which I use to store document authors in): if that field contains the current user’s username or one of its roles the user is allowed to edit.
Here’s the function:
function isAuthor( doc:NotesDocument ) {

    var level = doc.getParentDatabase().getCurrentAccessLevel();
        
    if (level >= 4) {
        return true;        //editor or higher
    } else if (level < 3) {
        return false;        //reader or lower
    } else {    //author
        
        var authors = doc.getItemValue("docAuthors");        //field containing all document authors
        if (authors === null) { return false; }        //no authors field present
        
        var userName = @UserName().toLowerCase();
        var roles = context.getUser().getRoles();  

        for (var i=0; i<authors.length; i++) {
            if (authors[i].substring(0,1) == "[") {        //role
                for (var j=0; j<roles.length; j++) {
                    if (authors[i].toLowerCase() == roles[j].toLowerCase()) {        //on of user's roles is in authors field
                        return true;
                    }
                }
                
            } else if (authors[i].toLowerCase() === userName ) {    //username matches one of the values in the authors field
                return true;
            }
        }
    }  

    return false;
} 

UPDATE 1 Serdar Basegmez came up with a Java version for this function. Since he’s from Turkey it will probably even work for users with a dotless-i in their name 🙂

 @SuppressWarnings("unchecked")
public static boolean isAuthor(Document doc, String authorField) {
               
  try {
    Database db=doc.getParentDatabase();
    Session session=db.getParent();
                       
    int level = db.getCurrentAccessLevel();
                             
    if (level >= 4) {
      return true;        //editor or higher
    } else if (level < 3) {
      return false;        //reader or lower
    } else {    //author
   
      Vector<String> authors=doc.getItemValue(authorField);
 
      if (null==authors || authors.isEmpty()) { return false; }        //no authors field present
                         
      Vector<String> checkList=session.evaluate("@UserNamesList");
                           
      for(int i=0; i<checkList.size(); i++) {
        String checkStr=checkList.get(i);
        checkList.set(i, checkStr.toLowerCase(Locale.ENGLISH));
      }
     
      for (int i=0; i<authors.size(); i++) {
        String checkStr=authors.get(i);
        if(checkList.contains(checkStr.toLowerCase(Locale.ENGLISH))) {
          return true;
        }
      }
    }
  } catch (NotesException e) {
    // Nothing to do
  }
         
  return false;
}

UPDATE 2: Philipp Bauer mentioned that you can also check if the current user is allowed to edit a document with the built-in isDocEditable() function:

import com.ibm.domino.xsp.module.nsf.NotesContext;
import lotus.domino.NotesException;

public static boolean isAuthor(Document doc) throws NotesException {
   NotesContext localNotesContext = NotesContext.getCurrent();
   return localNotesContext.isDocEditable(doc);
}

4 thoughts to “XPages “Change document mode” not working (and why)”

  1. Great! Thanks for this Mark. Only piece missing is to also check if the document is currently being edited and if it is, to hide it 🙂

    Dan

  2. Mark, this is useful… but, suppose the author is in a group that is in the docAuthors field? Seems like this function would need to also get the groups using context.getUser().getGroups() and see if that group was in the field too?

    Howard

    1. You’re right: the function doesn’t account for groups in the author field. Your addition will probably make it work for that scenario too!

      Mark

  3. If using the above formula by copying it, “function isAuthor” etc, strip all non-breaking spaces out of it first, or you’ll get errors in xpages.

Comments are closed.