I have modified the form's on web access, display xPage instead property and tried on runtime open selected document using xPage associated with the doucments form option, but this does not work. The current database is added at the start of the URL:
http://localhost/Requ%C3%AAtes852.nsf/%24%24OpenDominoDocument.xsp?databaseName=CN=Jocelyn%20Smith/OU=CSSS%20IUGS/OU=Reg05/O=SSSS!!iugs%5Cphysiosad.nsf&documentId=08FF9DFFD10070F585257A7F0053C282&action=editDocument
I must be missing something really basic. Does anyone have a work around? Thanks
I found a work around by using a redirection page that reads the document id and database name from the URL parameters then redirects. I'ld be interested in improving upon this solution though.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view
xmlns:xp="http://www.ibm.com/xsp/core"
rendered="false"
viewState="nostate">
<xp:this.afterPageLoad><![CDATA[#{javascript://Redirects to a page in another application
var docid = param.documentId;
var paramdbname = param.databaseName;
var hostname = context.getUrl().getHost();
//Get dbName without host
start = paramdbname.indexOf('!!');
dbName = paramdbname.slice(start+2);
var redirectstring = 'http://'+hostname+'/'+dbName+'/%24%24OpenDominoDocument.xsp?documentId='+docid+'&action=editDocument';
try{
facesContext.getExternalContext().redirect(redirectstring);
}
catch(err)
{
//Handle errors here
}}]]></xp:this.afterPageLoad>
<xp:br></xp:br>
Redirects to a page in another application
Related
I have an Xpage with access set to public for clients to fill in a form. When I send the client the link to the page and they open it for the first time. Everything runs smoothly. However, if they close the browser and click on the link again they receive this error:
{Unexpected runtime error
The runtime has encountered an unexpected error.
Error source
Page Name:/xpClientForm.xsp
Exception
Could not open the document
Invalid universal id}
I am using a switch facet to cycle between forms depending on the client type.
The domino document id is being stored in a sessionScope beforepageload and the document dynamically computes it based on that sessionScope variable.
Here is the code:
SessionScope assignment on beforepageload
var cData = getClientData(id);
sessionScope.docId = cData.docID;
Document datasource
<xp:panel style="height:100px" id="pnlDocData">
<xp:this.data>
<xp:dominoDocument var="document1"
formName="frmA" action="editDocument"
documentId="#{javascript:sessionScope.docID;}" scope="request">
</xp:this.data>
</xp:panel>
However when i execute this custom control on a page that does not have public access. It runs fine with no issues irrespective of how many times i open the link.
Any help will be greatly appreciated.
You need to set ignoreRequestParams="true" on the dominoDocument datasource. Otherwise it's using the document ID in the URL or trying to create a new document, which the user probably doesn't have access to do.
Computing the document ID is the less common scenario, which is using the URL for document location is the default.
In the source of an xpage I have, RIGHT after the opening view tag...the following:
<xp:this.data>
<xp:dominoDocument
formName="myform"
var="document1"
</xp:this.data>
I need to be able to pull the value of any field for various functions. In a 'Server JavaScript' library I have this function, as a test:
function testThis(){
debugger;
var mystring = document1.getElementById("#{id:employeeTitle}");
console.log(mystring);
(...expecting everything in the element to be logged in the console.)
You can see I have the XPage bound to a DominoDocument with the variable name of 'document1'.
The function is called via a button, and stops for the debugger...so I can step through it.
In Firefox debugger, it is 'Paused at an exception' that says:
ReferenceError: document1 is not defined
I am sure this is something simple staring right at me, but I just don't get it. Any ideas?
Thank you.
I think you are mixing up ServerSide JS and client side. The Firefox debugger only knows about client side debugging (which is code that executes in the browser). For debugging server side JS I suggest the Debug Toolbar plugin that you can find at open NTF.https://www.openntf.org/main.nsf/project.xsp?r=project/XPage%20Debug%20Toolbar
You can also write to the server log with _dump, see https://xcellerant.net/2014/10/15/using_dump_to_write_to_server_console/
Finally, note in your code that if SSJS, you would use document1.getItemValueString("whatever") to access document values. The document object is of type NotesXSPDocument. See https://www.ibm.com/support/knowledgecenter/en/SSVRGU_9.0.1/reference/r_wpdr_xsp_xspdocument_r.html
You get the DOM element of the rendered field employeeTitle on client side in your CSJS code with
var element = document.getElementById("#{id:employeeTitle}");
and the content value with element.innerHTML.
Use document (entry point to web page loaded in the browser) instead of document1 (usually named XPage's data source on server side).
Your function testThis() has to be a part of the XPage, Custom Control or a SSJS library. This makes sure that #{id:employeeTitle} gets replaced with the real DOM id on server during rendering. If you want to put testThis() into a CSJS library you have to deliver the id as parameter to the function like
function testThis(id){
var element = document.getElementById(id);
...
and call the function in XPage like
testThis("#{id:employeeTitle}");
Am coming across an intermittent problem when opening an Xpage. I have a button on a dialog to open another XPage in a new browser window, the code in the button is
var path = facesContext.getExternalContext().getRequest().getContextPath();
var xpage = "Claim.xsp"
var fullpath = path + "/" + xpage;
var url = fullpath + "?action=openDocument&documentId="+ Action.claimDocID
view.postScript("window.open('" + url + "')"
(if anyone has another way instead of the view.postScript let me know, just couldn't figure out how to open in a new browser window)
Occasionally when the window opens I'll get an error - Could not open document, below is the entry in the log.
05/04/2017 08:26:10 AM HTTP JVM: CLFAD0131E: Unable to push data because: Could not open the document. For more detailed information, please consult error-log-0.xml located in C:/IBM/Domino/data/domino/workspace/logs
05/04/2017 08:26:10 AM HTTP JVM: com.ibm.xsp.webapp.FacesServlet$ExtendedServletException: com.ibm.xsp.FacesExceptionEx: Could not open the document
CLFAD0131E: Unable to push data because: Could not open the document com.ibm.xsp.FacesExceptionEx: Could not open the document at com.ibm.xsp.model.domino.DominoDocumentData.doOpenDocument(DominoDocumentData.java:529) at com.ibm.xsp.model.AbstractDocumentDataSource.openDocument(AbstractDocumentDataSource.java:148) at com.ibm.xsp.model.AbstractDocumentDataSource.load(AbstractDocumentDataSource.java:100) at com.ibm.xsp.model.AbstractDataSource.getDataContainer(AbstractDataSource.java:474) at com.ibm.xsp.model.domino.DominoDocumentData.getDataObject(DominoDocumentData.java:165) at com.ibm.xsp.model.AbstractDataSource.pushData(AbstractDataSource.java:576) at com.ibm.xsp.util.DataPublisher.publishControlData(DataPublisher.java:181) at com.ibm.xsp.component.UIViewRootEx.publishControlData(UIViewRootEx.java:1288) at com.ibm.xsp.component.UIViewRootEx.initBeforeContents(UIViewRootEx.java:1615) at com.ibm.xsp.page.compiled.AbstractCompiledPage.init
<-- is from the error-log-0.xml
BUT, when I press reload on the browser the page loads, so the URL is correct. I placed all sorts of print statements on the XPage, in the Java managed bean it also uses, and when the error occurs nothing is printed. The error is immediate, whereas when reloading it takes time and the messages are printed. After the first error, it doesn't occur again.
A couple of other things about this application, it is password protected, it is running on HTTPS. The XPage it loads does have a Notes document that's located in another database plus it uses a Managed bean. If anyone has any ideas be grateful.
Thanks
Cameron
In regards to opening a given page in a new tab: have you tried using a link control instead of a button? Set a computed target url (preferably under "All Properties >> data >> value") AND set the target property to "_blank" ("All Properties >> basics >> target")
Using css you can later on modify the link to look like a button, if that's needed.
Btw: in general there's no need to calculate the path if you stay within the same database; the XSPcontext sees the .nsf as a common root. Just have your url point to "/myNewPage.xsp" then add the query string accordingly, like
var url = "/" + xpage + "?action=openDocument&documentId="+ Action.claimDocID
This error happens when universal ID provided to documentId URL parameter is invalid - possibly a document from another database or user has no access to it (readers field).
Just use a link with a target="_blank" parameter:
<xp:link value="/my_page_name.xsp" text="to the infinity and beyond" target="_blank">
<xp:this.parameters>
<xp:parameter name="action" value="openDocument" />
<xp:parameter name="documentId" value="#{Action.claimDocID}" />
</xp:this.parameters>
</xp:link>
I have same error. In My Case I was remove field In Shared Elements. After Field was restored, error is disappear.
I have a front end document locking process that creates an Application Scope variable with the UNID/Username/time in it, then a timer that updates this information every 30 seconds. If someone tries opening the document to edit I check (using the UNID) to see if anyone else has the document. If the time is greater than 30 seconds I cancel the lock and allow the new user to open it.
I have considered do something similar with a database 'lock' which is pretty simple but I need a unique Identifier of the browser session. I can build the applicationScope variable using ReplicaID/UserName/time but I need one more piece of information that will identify this browser session.
Is there such a piece of information available somewhere? Something like a browser sessionID?
You want to allow only one open browser window/tab per user and database.
For every XPage you open in browser you have to test if the same database is open in another browser window/tab already. If so, decline opening XPage with e.g. redirecting to an error XPage.
It is impossible to do this on server side only as the server don't know in which browser tab an Xpage gets opened.
So, the server needs client's help. The client have to give the server a unique browser window/tab id.
A browser window/tab doesn't have a unique id. But, opening a new window/tab we can create an random id and store it in browsers sessionStorage. This is a unique storage for every window/tab.
This window/tab id can be send to server with a partial refresh GET and stored on server for the user in an application scope variable.
Also, the server has to know when a window/tab gets closed so that the same database can be opened in another window/tab. For this the client has to tell the server "I am alive" every X seconds.
This is the complete solution:
Create a Custom Control "UniqueBrowserTab"
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:eventHandler
event="onClientLoad"
submit="false">
<xp:this.script><![CDATA[
var secondsIamAliveInterval = 5;
var tabId = sessionStorage.getItem("tabId");
if (!tabId) {
tabId = Math.random();
sessionStorage.setItem("tabId", tabId);
}
function sendTabIdToServer() {
XSP.partialRefreshGet("#{id:browserTabControl}", {
params: {'tabId': tabId}
});
}
sendTabIdToServer();
setInterval(function() {
sendTabIdToServer();
}, secondsIamAliveInterval * 1000);
]]></xp:this.script>
</xp:eventHandler>
<xp:panel id="browserTabControl">
<xp:this.rendered><![CDATA[#{javascript:
var secondsIgnoreOtherSession = 7;
if (param.tabId) {
var userName = session.getEffectiveUserName();
var userData = applicationScope.get(userName);
var now = new Date().getTime();
if (userData) {
if (userData.tabId !== param.tabId) {
if (userData.time + secondsIgnoreOtherSession*1000 > now) {
context.redirectToPage("Error.xsp");
}
}
}
applicationScope.put(userName, {tabId : param.tabId, time: now});
}
return true
}]]></xp:this.rendered>
</xp:panel>
</xp:view>
Include the Custom Control "UniqueBrowserTab" into every XPages or e.g. into application layout's Custom Control.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view
xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xc="http://www.ibm.com/xsp/custom">
<xc:UniqueBrowserTab />
...
</xp:view>
Create an XPage Error.xsp wich has not included the Custom Control "UniqueBrowserTab".
This will allow only one browser window/tab per database for a user across all browsers.
There is the SessionID cookie which is unique for the browser. I believe it's passed as part of the partial refresh information.
Just bear in mind that the SessionID would be the same for multiple windows of the browser. I'm not sure if that is an issue.
Thanks to all that have posted here. In actual fact there are two similar but different issues.
In the first instance it is to block multiple instances of the application in the same browser, and Sven's post answers that one.
The second issue is opening the same application in multiple browsers. In this case I am going to use an applicationScope variable appSession which is a Map with the key being UserName~DBRepID then two 'fields'
Time which is refreshed by a Client Side timer event which updates the time every "N" seconds.
sessionID = facesContext.getExternalContext().getRequest().getSession().getId();
In the before page loads (perhaps as a PhaseListener ??) I lookup appSession with the key UserName~RepID if the sessionID matches open the page. if the Time in appSession is time expired then set the time to the current time and set the sessionID to the current getID() and open the page. If not then open error page.
The sessionID has to have a timer on it so that if the user closes the browser or tab it will eventually time out. I'm using something like this for an XPage Document locking routine and it works well.
I have not put this all together yet but it looks to me as if it should get the job done. If anyone see a better way to do this I would be happy to hear.
Is there a way for a web user of an xpages based webpage to be able to show (read mode only) a document that is in a database where annonymous doesn't has acces to in the acl.
If I had access I could get the the document with for example :
https://servername/otherdatabase.nsf/O/"+thisid+"/$FILE/"+thisdocument
I guess it must be possible with SessionAsSigner , but how ?
Secondly is there a way for this user to see a view from a database where anonymous doesn't has acces to ? How can I set this up ?
Another option is to use an XAgent; for example, set the beforeRenderResponse event to the following:
var fileDb = sessionAsSigner.getDatabase((param.server || ""), param.path);
var fileDocument = fileDb.getDocumentByUNID(param.id);
var attachment = fileDocument.getAttachment(param.filename);
var inputStream = attachment.getInputStream();
var response = facesContext.getExternalContext().getResponse();
/* The following MIME type is generic, should work for all image types;
If you know what type the image will be, set a more specific MIME type */
response.setContentType("application/octet-stream");
var outputStream = response.getOutputStream();
com.acme.xsp.util.StreamUtil.copyStream(inputStream, outputStream);
inputStream.close();
outputStream.close();
attachment.recycle();
fileDocument.recycle();
facesContext.responseComplete();
com.acme.xsp.util.StreamUtil refers to a Java convenience class for pipelining one stream to another:
public class StreamUtil {
public static void copyStream(InputStream input, OutputStream output) throws IOException {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
}
}
So instead of linking your image tag directly to the attachment, it would look something like this:
<xp:image url="/download.xsp?server=ACME01&path=images.nsf&id=OU812&filename=photo.jpg" />
This approach would also afford you other options: logging how many times a given file is accessed, referer URL (in case you want to implement the "no hotlinking" image replacement you sometimes see when searching Google for images), or really anything you want.
As a specific example, about a decade ago I saw a coworker implement a basic in-house equivalent to Google Analytics that even worked on browsers that didn't support JavaScript because he used this technique for the company logo on every page of the site: instead of linking directly to the logo JPG, he linked to a PHP file that grabbed IP, referer, user agent, etc., wrote all of the metadata out to a MySQL database, then finally streamed the bytes of the logo to the browser. This is obviously outside the scope of what it sounds like you're trying to accomplish, but I figured you might find it interesting that this type of use case is rather simple now in XPages.
This is possible using sessionAsSigner and for instance a repeat. If the XPage is in the same database, then make sure to mark the XPage as available for public access. The follwing simple example will display content from the view columns and an image from the document:
<xp:repeat id="protectedView" rows="15" removeRepeat="true" var="rowEntry" disableOutputTag="true">
<xp:this.value><![CDATA[#{javascript:
var thisDb = sessionAsSigner.getDatabase(database.getServer(), database.getFilePath());
var aView = thisDb.getView("protectedView");
return staffView.getAllEntries(); // return collection of docs
}]]></xp:this.value>
<xp:text>
<xp:this.value><![CDATA[#{javascript:rowEntry.getColumnValues().elementAt(1)}]]></xp:this.value>
</xp:text>
<xp:br />
<xp:text>
<xp:this.value><![CDATA[#{javascript:rowEntry.getColumnValues().elementAt(2)}]]></xp:this.value>
</xp:text>
<xp:br />
<xp:inputRichText id="inputRichText1" readonly="true">
<xp:this.value><![CDATA[#{javascript:
// wrap NotesDocument into NotesXspDocumenet to easily display picture
wrapDocument(rowEntry.getDocument()).getValue("Picture");}]]></xp:this.value>
</xp:inputRichText>
</xp:repeat>
I use the wrapDocument XSnippet to convert NotesDocument into NotesXspDocument.
Essentially this is impossible.
You could construct the URL using sessionAsSigner but when the user tries to access the document / image they will get an unauthorized exception.
The only way you could display the view of data would be to read the contents of the view into a scoped variable (or bean) using sessionAsSigner and then display a repeat control that references the data from the scoped variable instead of the view directly.
The larger question is why you want to do this. If Anonymous can't have access to the database in question then there's a good reason for this. Another alternative would be to think about using $PublicAccess flags on the documents / views that you want to give Anonymous access to. Then on the ACL, as long as Anonymous can read public data then they can still have no access to the database.
Matt