Xpages - Creating Repeat or View from different database with ACL set to No Access - xpages

I am trying to create a repeat element from a view in a different database that does not allow Anonymous ACL access.
PubDb.nsf has ACL set for user Anonymous to Author
PrivDb.nsf has ACL set for user Anonymous and Default "no access".
The database, PrivDb has information that I want to secure, but would like to pull a couple of views out for public display.
When I create a repeat in PubDb.nsf using PrivDb.nsf view, It will not display any data. I am able to use sessionAsSigner to get SSJS to see the view and open documents at the server side level, but when I try to display the view or repeat elements there is no data ? If I change ACL in PrivDb for Anonymous to Reader everything works, but now the entire db is open to Anonymous access.
I understand that sessionAsSigner and sessionAsSignerWithFullAccess allows me to use db signers effective rights, and I can use SSJS to access the notesdocuments and publish data using computed fields for individual docs, but I can't find any information that tells me I can or can't display an xpages element (repeat or view) using the sessionAsSigner. Maybe I can create a lotusscript agent that populates the block?
Below is the code I use to create the repeat element in PubDb.nsf. Note, I assigned the DB twice, once in Application and again in View because when I didn't use sessionAsSigner in the view's computed value I would get prompted for authentication, and it's required in the app field.
<xp:this.data>
<xp:dominoView var="view2">
<xp:this.databaseName><![CDATA[${javascript:
var DB:NotesDatabase=sessionAsSigner.getDatabase(database.getServer(),"PrivDb.nsf");
DB;
}]]>
</xp:this.databaseName>
<xp:this.viewName><![CDATA[${javascript:
var dbOther:NotesDatabase = sessionAsSignerWithFullAccess.getDatabase(database.getServer(), "PrivDb.nsf");
var lookupView:NotesView = dbOther.getView( "PrivView" );
lookupView.recycle();
lookupView}]]>
</xp:this.viewName>
</xp:dominoView>
</xp:this.data>
<div class="container">
<div class="page-header">
<h1>This is a test.</h1>
</div>
<xp:br></xp:br>
<xp:br></xp:br>
<div class="row">
<div class="col-md-1"></div>
<div class="col-md-10">
<xp:repeat id="repeat1" rows="30" var="playerData"
value="#{view2}" repeatControls="true">
<div class="panel panel-default">
<xp:text escape="true" id="computedField1"
value="#{playerData.$5}">
</xp:text>
hcp:  
<xp:text escape="true" id="computedField5"
value="#{playerData.$6}">
</xp:text>
<xp:br></xp:br>
<xp:text escape="true" id="computedField2"
value="#{playerData.$7}">
</xp:text>
   
<xp:text escape="true" id="computedField3"
value="#{playerData.$8}">
</xp:text>
   
<xp:text escape="true" id="computedField4"
value="#{playerData.$9}">
</xp:text>
<xp:br></xp:br>
</div>
<div class="col-md-1"></div>
</xp:repeat>
</div>
</div>
</div>

Try changing your repeat to return for instance the view entries directly using sessionAsSigner instead of going through a view data source. So in your case:
<xp:repeat id="repeat1" rows="30" var="playerData">
<xp:this.value><![CDATA[#{javascript:
sessionAsSigner.getDatabase(database.getServer(), "PrivDb.nsf").getView("PrivView").getAllEntries();
}]]></xp:this.value>
...
</xp:repeat>

Related

Can I display HTML in Error Messages control?

In my XPages application we are using Bootstrap for theming.
If I look at the alert component:
<div class="alert alert-danger" role="alert"> <strong>WARNING</strong> SYSTEM FAILURE. </div>
I see a element is used.
Now in my XPages application I used something as followed:
FacesContext.getCurrentInstance().addMessage(null, new javax.faces.application.FacesMessage(javax.faces.application.FacesMessage.SEVERITY_ERROR, "<strong>WARNING</strong> SYSTEM FAILURE", ""));
but this is displayed as text:
Is it somehow to make the Error Messages control display HTML?
You can write your own message control like this:
<xp:panel styleClass="xspMessage"
rendered="#{javascript:facesContext.getMessages().hasNext()}">
<xp:repeat id="repeat1" rows="30" var="msg">
<xp:this.value><![CDATA[#{javascript:var v = new java.util.Vector();
var itr = facesContext.getMessages()
while(itr.hasNext()) {
var element:javax.faces.application.FacesMessage = itr.next();
v.add(element.getSummary())
}
return v;}]]></xp:this.value>
<xp:text escape="false" id="computedField1" value="#{msg}" tagName="div">
</xp:text>
</xp:repeat>
</xp:panel>
A better way would be to use CSS to format the error messages control output.

XPages view data source and limit to single category

I have a categorized view that I am using as a view data source in an XPage. I have set the categoryFilter of the data source so that only the call history of the selected individual (for a given incident) is displayed. The filter being stored in the sessionScope is a concatenation of the UniqueID of the person and the IncidentID. The lookup view is categorized by that value.
One would expect that to work, however the filtering does not seem to be working and I can see all call histories regardless of the person I choose. I've done this before and I must be missing something obvious.
I have verified the sessionScope.callHistoryID is being updated as I select a new person. My Call History db currently only has 2 history documents for one guest, yet they display for every guest in the Xpage.
sessionScope.callHistoryID from the debugger is obviously not the same (see below):
<xp:panel id="pnlCallHistoryModal" style="padding-bottom:20px">
<xp:this.data>
<xp:dominoView var="callhistoryView"
viewName="luCallHistorybyPaxandIncidentID"
databaseName="blah.nsf"
ignoreRequestParams="true"
categoryFilter="#{javascript:sessionScope.callHistoryID}">
</xp:dominoView>
</xp:this.data>
<div class="col-xs-12 col-md-12 col-lg-12 panel-body">
<xp:repeat id="repeat1" value="#{callhistoryView}"
var="viewRow" indexVar="rowIndex" rows="500"
repeatControls="false">
<xp:this.facets>
<xp:text disableTheme="true" xp:key="header"
escape="false">
<xp:this.value><![CDATA[
<table class="table table-hover">
<tbody>]]></xp:this.value>
</xp:text>
<xp:text disableTheme="true" xp:key="footer"
escape="false">
<xp:this.value><![CDATA[
</tbody>
</table>]]></xp:this.value>
</xp:text>
</xp:this.facets>
<xp:tr>
<xp:this.rendered><![CDATA[# {javascript:if(viewRow.isCategory()){
return false
}else{
return true
}}]]></xp:this.rendered>
<xp:td styleClass="col-md-10 col-lg-10 small">
<xp:text escape="true" id="name">
<xp:this.value><![CDATA[#{javascript:#ProperCase(viewRow.getColumnValue("CallerFullName"))}]]></xp:this.value>
</xp:text>
<br></br>
<xp:text escape="true" id="computedField1"
styleClass="small secondary-text">
<xp:this.value><![CDATA[#{javascript:if(viewRow.getColumnValue("CallerMemo").length > 128){
return viewRow.getColumnValue("CallerMemo").substring(0,128) + " ..."
}else{
return viewRow.getColumnValue("CallerMemo")
}}]]></xp:this.value>
</xp:text>
</xp:td>
<xp:td styleClass="col-md-2 col-lg-2 small">
<xp:text escape="true" id="creationdatetime"
styleClass="small">
<xp:this.value><![CDATA[#{javascript:viewRow.getColumnValue("CallDateTime")}]]></xp:this.value>
<xp:this.converter>
<xp:convertDateTime type="both"
dateStyle="short" timeStyle="short">
</xp:convertDateTime>
</xp:this.converter>
</xp:text>
</xp:td>
</xp:tr>
</xp:repeat>
</div>
</xp:panel>
I suspect this will be doing the equivalent of ViewNavigator.createViewNavFromCategory(). It's worth checking how that acts if the category name doesn't exist. It may fall back to a partial match.
For "restrict to category", you might be better placed using the keys property and settings keysExactMatch to true.

XPages pager refresh issue

I have a problem with a pager performing a partial refresh (since we have server side redirection rules, full refresh is not an option here). If I place the pager on the same page rather than in a custom control then it refresh the main panel. But if I place the pager in a custom control, then it only updates the repeat control, which means the pager control itself doesn't get refreshed. Here is a simple example to demonstrate the problem.
<?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">
<xp:panel id="mainPanel">
<xc:ccPager pagerFor="repeat1" id="myPager" />
<xp:repeat id="repeat1" rows="3" var="row">
<xp:this.value><![CDATA[#{javascript:var cars = ["Saab", "Volvo", "BMW", "Saab", "Volvo", "BMW"];
return cars; }]]></xp:this.value>
<xp:text escape="true" id="computedField1" value="#{row}">
</xp:text>
</xp:repeat>
</xp:panel>
</xp:view>
And here is the code for the custom control:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:pager layout="Previous Group Next" partialRefresh="true"
id="pager1" for="#{compositeData.pagerFor}" partialExecute="false">
</xp:pager>
</xp:view>
Any tips would be welcome. In this case the pager is simple, but I have a more complex pager and a pagesizes control with 45 lines of source code, so I would prefer to create a re-useable custom component if possible at all.
UPDATE
My current pager custom control:
<div id="page-result" class="pagination pagination-small clearfix">
<div class="col-lg-12 pagination clearfix">
<div class="results form-inline left">
<fieldset>
<xp:pager id="pager1" alwaysCalculateLast="true"
for="#{compositeData.strPagerFor}" styleClass="pag-control"
partialRefresh="true" partialExecute="false">
<xp:pagerControl id="pagerControl1" type="FirstImage"
styleClass="firstPage" image="/PagerArrowhead2-L_d.png">
</xp:pagerControl>
<xp:pagerControl id="pagerControl2" type="PreviousImage"
styleClass="previousPage" image="/PagerArrowhead-L_d.png">
</xp:pagerControl>
<xp:pagerControl id="pagerControl5" type="Group"
currentStyleClass="active" styleClass="pages">
</xp:pagerControl>
<xp:pagerControl id="pagerControl3" type="NextImage"
styleClass="nextPage" image="/PagerArrowhead.png">
</xp:pagerControl>
<xp:pagerControl id="pagerControl4" type="LastImage"
styleClass="lastPage" image="/PagerArrowhead2.png">
</xp:pagerControl>
</xp:pager>
<label>
<xp:text escape="true" id="computedField1" value="#{compositeData.strLabelText}" />
</label>
</fieldset>
</div>
<div class="results form-inline">
<fieldset>
<label> Results per page: </label>
<xe:pagerSizes id="pagerSizes1" for="#{compositeData.strPagerFor}"
sizes="7|15|25|50|all" text="{0}" styleClass="resultPage"
partialRefresh="true" partialExecute="false"
refreshId="#{compositeData.strRefreshPanel}" />
</fieldset>
</div>
</div>
</div>
I've hit this problem before. I think it's because the view container cannot find the pager when it's in a separate custom control. I presume it's using something like getComponent, which can't navigate down into custom controls, so it can't locate the pager to update it.
Can you extract the code for your pagesizes control into a Java dataObject / bean / util or dataContext / SSJS library? Then reference it with one line of SSJS or EL?
The other option would be to use a plugin and build a component that extends the repeat control and adds the pager to the relevant header?
Tim Tripcony gave a great demo of a quick and dirty way of doing it http://www.notesin9.com/2012/04/04/notesin9-064-global-custom-controls-fixed/

How to create link to another database using link control?

How to create link to another database using link control? I thought that I simply start URL with slash but it doesnt work as xpages prepends path to current database to this link and I'm getting wrong link as this one: /app/projects.nsf/database.nsf/page.xsp
<xp:link escape="true" text="Link" id="link1" value="/database.nsf/page.xsp">
</xp:link>
I know that I can create absolute link starting with http:// but I would like to avoid this ...
You can use the xp:text element and convert it to an anchor:
<xp:text escape="true" id="link1" tagName="a" value="Link">
<xp:this.attrs>
<xp:attr name="href" value="/database.nsf/page.xsp"></xp:attr>
</xp:this.attrs>
</xp:text>
Or add the link as Passthrough Tag.
If the database is in the same sub-directory on the server, you can use ../xxx.nsf
For every sub-folder you want to go back, you can prepend a ../
Example in your case:
<xp:link escape="true" text="Link" id="link1" value="../database.nsf/page.xsp">
</xp:link>
If the database would be one folder above the current databases' folder you can use this:
<xp:link escape="true" text="Link" id="link1" value="../../database.nsf/page.xsp">
</xp:link>
Hope that helps.
Michael
To build on Sven's answer, I computed the URL, and set the target to be a new tab.
So my xp:text element is:
<xp:text id="label4" escape="true"
styleClass="btn btn-default" value="Open Fastworks Document"
tagName="a">
<xp:this.attrs>
<xp:attr name="href">
<xp:this.value><![CDATA[#{javascript:var sUNID = document1.getItemValueString("FWUNID");
var sNSF = document1.getItemValueString("FWNSF").replace("\\","/");
//sys_all/A4DC4CFDA12A1A4E80257F48003DD8F9?OpenDocument
"/"+sNSF + "/sys_all/"+sUNID;}]]></xp:this.value>
</xp:attr>
<xp:attr name="target"
value="_blank">
</xp:attr>
</xp:this.attrs>
</xp:text>
This then produces HTML such as :
<a class="btn btn-default" id="view:_id1:_id2:callback2:label4" href="/Fastworks/Version52m/Accident.nsf/sys_all/31F7D581D23BCFE580257FA1002E3B43" target="_blank">Open Fastworks Document</a>

Xpages Dynamic dojo dialog control

I have a list of products (created using a repeat control) and wish to click on a particular product and bring up a dialog with further information about that particular product. I don't really want to generate dijit.dialog thing for every single product on that page, so how can I do this dynamically possibly using AJAX and partial refresh.
A similar non xpages example can be seen here: http://www.replacementkeys.co.uk/window?dir=asc&limit=12&mode=grid&order=position - where you hover over an image and a quick view button comes up, which then dynamically loads the content for that product.
Any ideas would be truly appreciated.
We build the dialog outside the repeat control and then the action that launches or shows it also sets a viewScope variable that is used UNID for the data source in the dialog. Just make sure you refresh the contents of the dialog as you open it...
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xe="http://www.ibm.com/xsp/coreex">
<xp:this.data>
<xp:dominoView var="promptView" viewName="dlgBoxes">
</xp:dominoView>
</xp:this.data>
<xp:panel>
<xp:repeat id="repeat1" rows="30" value="#{promptView}" var="promptEntry">
<xp:panel tagName="div">
<xp:text escape="true" id="computedField1" value="#{promptEntry.dlgName}">
</xp:text>
 
<xp:button value="details" id="button1">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:
var pe:NotesViewEntry = promptEntry;
viewScope.put("dlgDocUnid", pe.getUniversalID());
getComponent("dialog1").show();
}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:panel>
</xp:repeat>
</xp:panel>
<xe:dialog id="dialog1" keepComponents="false" partialRefresh="true">
<xe:this.title><![CDATA[#{javascript:
var unid = viewScope.get("dlgDocUnid");
if(!unid) return "";
var doc:NotesDocument = database.getDocumentByUNID(unid);
return doc.getItemValueString("dlgName");}]]></xe:this.title>
<xp:panel>
<xp:this.data>
<xp:dominoDocument var="dlgDoc" formName="dlgBox" action="openDocument">
<xp:this.documentId><![CDATA[#{javascript:viewScope.get("dlgDocUnid");}]]></xp:this.documentId>
</xp:dominoDocument>
</xp:this.data>
<xp:text escape="true" id="computedField2" value="#{dlgDoc.Title}">
</xp:text>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:text escape="true" id="computedField3" value="#{dlgDoc.dlg}">
</xp:text>
</xp:panel>
</xe:dialog>
</xp:view>
Happy coding
/Newbs
You can combine your repeat control with the Extension Library dialog control in order to be able to launch a dialog when the user clicks on the individual row. Chris Toohey has created an excellent article called Popup Dialog Forms from Views in XPages that demonstrates this.

Resources