Getting an Error message when trying to appendDocLink is SSJS - xpages

Not sure what I'm doing wrong, but here is the code
1: var currDoc:NotesDocument = currentDocument;
2: var doc:NotesDocument = database.createDocument();
3: doc.replaceItemValue("form", "Memo");
4: doc.replaceItemValue("sendTo", currDoc.getItemValueString("responsible"));
5: doc.replaceItemValue("subject", currDoc.getItemValueString("replySubject"));
6: var rtitem:NotesRichTextItem = doc.createRichTextItem("Body");
7: rtitem.appendText("The following more information request has been answered:");
8: rtitem.addNewLine(2);
9: rtitem.appendText("Subject: " + currDoc.getItemValueString("replySubject"));
10: rtitem.addNewLine(2);
11: rtitem.appendText("Reply Text: " + currDoc.getItemValueString("replyText"));
12: rtitem.addNewLine(2);
13: rtitem.appendDocLink(currDoc);
14: doc.send();
Problem on line 13 (what are the chances of that)
Error while executing JavaScript action expression
Script interpreter error, line=13, col=8: [TypeError] Method NotesRichTextItem.appendDocLink(NotesXspDocument) not found, or illegal parameters, when I comment out line 13 the rest of the code works fine, sends the email with the content from the document I am trying to pass to the email.

Couple of things...
First of all make sure that your NSF has a default view setup. Doclinks won't work if there is no default view. You can tell if there is a default view by the presence of a gold star beside one of the views in designer.
From the error message it looks like your passing a NotesXspDocument into the appendDocLink method while it is expecting a NotesDocument. the first line of code should really be
var currDoc:NotesDocument = currentDocument.getDocument(true)
Also, has the document been saved at this point, if not then you should add a line
currDoc.save(true,true)
and this will make sure that the document is saved, You can't send a DocLink without the document UNID and an unsaved document will not have a valid UNID.

Related

How to handle a system.InvalidOperationException when converting from System.windows.FormsMessageBox to Xceed.Wpf.Toolkit.MessageBox

I have a very bland messagebox asking my users a simple question (not yes or no). For quick development I used a simple System.Windows.Forms.MessageBox and worded the question ("If you want to choose 'A' click 'Yes' if you want to choose 'B' click 'No'"). Now I'm going back and improving the look and feel of my wpf application and I'm stuck trying to convert this MessageBox into something that looks good.
My preliminary search told me to use Xceed.Wpf.Toolkit.MessageBox to be able to create custom message box but I'm getting an exception when I'm trying to use it.
Old Code
DialogResult dialogResultForDataDisplay = System.Windows.Forms.MessageBox.Show("Yes: Display by properties \n \t Each row will contain data for a specific asset class in a specific submarket during a specific quarter. \n \n No: Display by quarters \n \t Each row will will show the change over time for a specific property of an asset class in a specific submarket.", "Data Grouping Format", MessageBoxButtons.YesNo);
New Code
Style style = new Style();
style.Setters.Add(new Setter(Xceed.Wpf.Toolkit.MessageBox.YesButtonContentProperty, "By Property"));
style.Setters.Add(new Setter(Xceed.Wpf.Toolkit.MessageBox.NoButtonContentProperty, "By Quarter"));
MessageBoxResult result = Xceed.Wpf.Toolkit.MessageBox.Show("How do you want your information displayed?", "My caption", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.Yes, style);
Console.WriteLine(result);
The new code is generating this exception: System.InvalidOperationException: 'The calling thread must be STA, because many UI components require this.'
How would you go about handling this exception?
One solution I found now is rapping it in an invoke method. If someone has a better solution please post.
MessageBoxResult result = MessageBoxResult.None;
System.Windows.Application.Current.Dispatcher.Invoke((Action)delegate
{
Style style = new Style();
style.Setters.Add(new Setter(Xceed.Wpf.Toolkit.MessageBox.YesButtonContentProperty, "Yes, FTW!"));
style.Setters.Add(new Setter(Xceed.Wpf.Toolkit.MessageBox.NoButtonContentProperty, "Omg, no"));
result = Xceed.Wpf.Toolkit.MessageBox.Show("How do you want your information displayed?", "My caption", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.Yes, style);
}
Console.WriteLine(result);

xpages copy field value to another field from other datasource

I followed How do you copy a datetime field from the current document to a new document and I try something like this:
Cdoc.save();
Pdoc.copyItem(Cdoc.getDocument().getFirstItem("mytest1"));
getComponent('exampleDialog').show()
But I get a handling error message.
Thanks for your time!
Assuming Cdoc and Pdoc are defined as xp:dominoDocument data sources then you have to change your code to:
Cdoc.save();
Pdoc.getDocument().copyItem(Cdoc.getDocument().getFirstItem("mytest1"));
getComponent('exampleDialog').show()
So, you only need to add .getDocument() to Pdoc to get the Notes Document. Otherwise it fails and you get the error "Error calling method 'copyItem(lotus.domino.local.Item)' on an object of type 'NotesXspDocument'".
Keep in mind that you have to save Pdoc after copying item too if you want to show the copied item in your exampleDialog.
If you don't want to save document Pdoc at this point yet then you can copy the item on NotesXspDocument level with just:
Pdoc.replaceItemValue("mytest1", Cdoc.getItemValueDateTime("mytest1"));
getComponent('exampleDialog').show()
I do not often use "copyItem". You are not specifying if you are using NotesDocuments or NotesXspDocuments, so I will write a quick thing about both because they should be handled differently.
var currentDoc:NotesDocument = ....
var newDoc:NotesDocument= ...
newDoc.replaceItemValue("fldname", currentDoc.getItemValueDateTimeArray("fldname").elementAt(0))
if currentDoc is a NotesXspDocument, use the following
var currentDoc:NotesXspDocument = ...
var newDoc:NotesDocument=...
newDoc.replaceItemValue("fldname", currentDoc.getItemValueDateTime("fldname"))
Otherwise, you could continue trying with copyItem, I just lack experience with it.
EDIT
Just some things to add, remember that putting calling xspDoc.getDocument(true) will update the background document and this might be needed. Also, in the comments for that article you posted, they mentioned the possible need to put that document into another variable.
var docSource:NotesDocument = xspDoc.getDocument(true);
var docNew:NotesDocument = ...
docNew.copyItem(docSource.getItem("blah");
Also remember that copyItem is a function of NotesDocument and not NotesXspDocument.

Cakephp get details about security component error

I am using security component in my projects and is there any way to get the detailed description about the error while developing ? For ex:- if any field is added in view without using cakephp's form method, it is returning error as 'auth' in my blackHoleCallback function. Instead I need beacuse of what reason it returned that error. Because it is taking so much time to rectify the problem. Is there any way to get the detailed error description ?
All you have to do is look in the right place
Check your app/tmp/logs/error.log file
If you look in the error log you'll see an entry like this:
2013-03-16 17:24:29 Error: [BadRequestException] The request has been black-holed
#0 root/lib/Cake/Controller/Component/SecurityComponent.php(228): SecurityComponent->blackHole(Object(FacebookUsersController), 'csrf')
#1 [internal function]: SecurityComponent->startup(Object(FacebookUsersController))
#2 root/lib/Cake/Utility/ObjectCollection.php(130): call_user_func_array(Array, Array)
#3 [internal function]: ObjectCollection->trigger(Object(CakeEvent))
#4 root/lib/Cake/Event/CakeEventManager.php(246): call_user_func(Array, Object(CakeEvent))
#5 root/lib/Cake/Controller/Controller.php(670): CakeEventManager->dispatch(Object(CakeEvent))
#6 root/lib/Cake/Routing/Dispatcher.php(183): Controller->startupProcess()
#7 root/lib/Cake/Routing/Dispatcher.php(161): Dispatcher->_invoke(Object(FacebookUsersController), Object(CakeRequest), Object(CakeResponse))
#8 root/app/webroot/index.php(96): Dispatcher->dispatch(Object(CakeRequest), Object(CakeResponse))
#9 {main}
Read the error that is on screen
If you are in debug mode, this error is also shown on screen when the error happens. e.g.:
The request has been black-holed
Error: The requested address '/admin/fooby/edit/1' was not found on this server.
Stack Trace
CORE/Cake/Controller/Component/SecurityComponent.php line 228 → SecurityComponent->blackHole(FacebookUsersController, string)
[internal function] → SecurityComponent->startup(FacebookUsersController)
CORE/Cake/Utility/ObjectCollection.php line 130 → call_user_func_array(array, array)
[internal function] → ObjectCollection->trigger(CakeEvent)
CORE/Cake/Event/CakeEventManager.php line 246 → call_user_func(array, CakeEvent)
CORE/Cake/Controller/Controller.php line 670 → CakeEventManager->dispatch(CakeEvent)
CORE/Cake/Routing/Dispatcher.php line 183 → Controller->startupProcess()
CORE/Cake/Routing/Dispatcher.php line 161 → Dispatcher->_invoke(FacebookUsersController, CakeRequest, CakeResponse)
APP/webroot/index.php line 96 → Dispatcher->dispatch(CakeRequest, CakeResponse)
Handling csrf errors
With the details of a specific error (i.e. the data you are posting, and the exact token data in your session at the time) it would be possible to answer what problem brought you here, in the absense of that:
look at the line throwing the error.
In the stack trace above, the error is coming from CORE/Cake/Controller/Component/SecurityComponent.php line 228 - Open the file and look what that code is:
if ($isPost && $isNotRequestAction && $this->csrfCheck) {
if ($this->_validateCsrf($controller) === false) {
return $this->blackHole($controller, 'csrf');
}
}
What should be obvious from this is that the function _validateCsrf is responsible for the request being blackholed. This should not really be much of a surprise.
Look at the source of that function:
protected function _validateCsrf(Controller $controller) {
$token = $this->Session->read('_Token');
$requestToken = $controller->request->data('_Token.key');
if (isset($token['csrfTokens'][$requestToken]) && $token['csrfTokens'][$requestToken] >= time()) {
if ($this->csrfUseOnce) {
$this->Session->delete('_Token.csrfTokens.' . $requestToken);
}
return true;
}
return false;
}
Depending on why that function returns false, determines how you continue to debug.
Correct configuration of the component
The inevitable consequence of debugging a CSRF error is you'll need to modify the configuration of the Security component.
Do you, for example, want to be reusing tokens, because your app is submitting the same form multiple times between page loads?
Are you self-invalidating the form requests by adding new fields to the form data - You can use the unlockedFields property to exclude these fields from the csrf checks.
You can also simply disable CSRF checks completey. That has obvious security consequences - but if you're struggling to work with the component, it's an easy way to work around and problems you currently face.
In order to see the mechanisms I dug into the code to see how the FormHelper hash is created vs. how the SecurityComponent validation checks the hash. Here's how to see exactly what is happening behind the scenes.
Checking the input to the FormHelper. Open CORE/Cake/View/Helper/FormHelper.php. In the secure() function add some pr lines around the $files=Security::hash line to see how the tokens are built:
pr($fields);//hashed into computed token on next line
$fields = Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt'), 'sha1');
pr($unlocked); //hashed into computed token
pr(Configure::read('Security.salt')); //hashed into computed token
pr($fields); //computed token passed via hidden token field in form
Check how form is processed
Now check how the submitted form is processed and compared to the passed token:
Open the CORE/Cake/Controller/Component/SecurityComponent.php. Insert some pr lines in the _validatePost() routine at the end:
pr($fieldList); //hashed into computed token
pr($unlocked); //hashed into computed token
pr(Configure::read('Security.salt')); //hashed into computed token
pr($token); //passed token from FormHelper
pr($check); //computed token
Hopefully this helps someone else who has problems with locked/unlocked or missing fields quickly figure out what is going on inside of your cake.
Remember also that you have to have an exact match between the Token generated by the FormHelper and that retrieved bu cake using Session. The mismatch can happen, as the doc says, when you dynamically generate input or when make ajax call: remember to serialize the form and submit it via ajax!
If you have input tag generated not generated by using the FormHelper, you have to unlock'em. For example in your beforeFilter():
$this->Security->unlockedFields =
array('MyModel.some_field1','MyModel.some_field2')
where field1 and field2 are fields generated "by hand", i.e. by not using the Helper.
To answer the question: "Is there any way to get the detailed error description?"
First thing is to add more valuable debugging to your controller when it comes to SecurityComponent. Here's one way to do it:
public function beforeFilter() {
parent::beforeFilter();
//your beforeFilter code
//Enable CSRF and other protections
$this->Security->csrfExpires = '+1 hour';
$this->Security->csrfUseOnce = true;
$this->Security->blackHoleCallback = 'blackhole';
}
public function blackhole($errorType) {
$errorMap['auth'] = 'form validation error, or a controller/action mismatch error.';
$errorMap['csrf'] = 'CSRF error.';
$errorMap['get'] = 'HTTP method restriction failure.';
$errorMap['post'] = $errorMap['get'];
$errorMap['put'] = $errorMap['get'];
$errorMap['delete'] = $errorMap['get'];
$errorMap['secure'] = 'SSL method restriction failure.';
$errorMap['myMoreValuableErrorType'] = 'My custom and very ' .
'specific reason for the error type.';
CakeLog::notice("Request to the '{$this->request->params['action']}' " .
"endpoint was blackholed by SecurityComponent due to a {$errorMap[$errorType]}");
}
As AD7six mentioned take a look at the CORE/Cake/Controller/Component/SecurityComponent.php. Specifically SecurityComponent::startup(). In that method you will notice that SecurityComponent::blackhole() method is ran a few times. It's ran whenever the criteria fails a security check and looks like this:
return $this->blackHole($controller, 'auth');
In this case 'auth' represents the type of security check that failed. You could customize the 'auth' string to be more valuable. For example instead of 'auth' use 'myMoreValuableErrorType' and then map that to something more meaningful.
So instead of running $this->blackHole($controller, 'auth') when a security check fails, you would run $this->blackHole($controller, 'myMoreValuableErrorType') and then map 'myMoreValuableErrorType' to a specific reason on why it failed by using the code above.

Repeat control error in xpage

JavaScript code
1: db=database;
2: theView=db.getView(compositeData.PDviewname);
Error while executing JavaScript computed expression
Script interpreter error, line=2, col=12: [TypeError] Exception occurred calling method NotesDatabase.getView(null) null
You don't catch null values. One possible way:
var viewName = compositeDate.PDViewName == null ? 'someDefaultName' | compositeDate.PDViewName;
var theView = database.getView(viewName);
Of course you could also stop the code if viewName is null. You shouldn't use sessionScope here -> your code will break if a user has the unheard idea of opening 2 browser tabs in your application.

Deleting list items via ProcessBatchData()

You can build a batch string to delete all of the items from a SharePoint list like this:
1: //create new StringBuilder
2: StringBuilder batchString= new StringBuilder();
3:
4: //add the main text to the stringbuilder
5: batchString.Append("");
6:
7: //add each item to the batch string and give it a command Delete
8: foreach (SPListItem item in itemCollection)
9: {
10: //create a new method section
11: batchString.Append("");
12: //insert the listid to know where to delete from
13: batchString.Append("" + Convert.ToString(item.ParentList.ID) + "");
14: //the item to delete
15: batchString.Append("" + Convert.ToString(item.ID) + "");
16: //set the action you would like to preform
17: batchString.Append("Delete");
18: //close the method section
19: batchString.Append("");
20: }
21:
22: //close the batch section
23: batchString.Append("");
24:
25: //preform the batch
26: SPContext.Current.Web.ProcessBatchData(batchString.ToString());
The only disadvantage that I can think of right know is that all the items you delete will be put in the recycle bin. How can I prevent that?
I also found the solution like below:
// web is a the SPWeb object your lists belong to
// Before starting your deletion
web.Site.WebApplication.RecycleBinEnabled = false;
// When your are finished re-enable it
web.Site.WebApplication.RecycleBinEnabled = true;
Ref [Here](http://www.entwicklungsgedanken.de/2008/04/02/how-to-speed-up-the-deletion-of-large-amounts-of-list-items-within-sharepoint/)
But the disadvantage of that solution is that only future deletion will not be sent to the Recycle Bins but it will delete all existing items as well which user do not want. Any idea to prevent not to delete existing items?
Many thanks in advance,
TQT
I don't think is possible to bypass the recycle bin using batch update however you could modify you code to something like this
foreach (SPListItem item in itemCollection)
{
item.Delete(); //this wont go to the recycle bin
//or if you need to send it to the recycle bin then you can use
item.Recycle();
}

Resources