How To Know When A CS Cart Hook Fires? - hook

I need to confirm if I have selected the right hook from the hooks database. I need to auto order a vehicle on confirming an order. I chose the change_order_status and registered it in my init.php using
fn_register_hooks(
'change_order_status'
);
now in my func.php I have
if (!defined('AREA')) {die('Access denied');}
function fn_dellyman_change_order_status(&$status_to,&$status_from,&$order_info,&$force_notification,&$order_statuses,&$place_order) {
//Getting authentication data to identify user
$auth = $_SESSION['auth'];
var_dump($auth);
}
when I go to orders and switch the order from say open to complete, I expect to see the contents of auth rendered to the page at least as part of the request response. However I see no indication that the hook selected is the right one. How can i ensure the hook called is correct.

depending on your CS-Cart version since 4.6.x is Tygh::$app['session']['auth'] but also depend if is done by AJAX request or normal place/edit order
On AJAX request you will not get any notification.
please try to use for a nicer notification:
fn_print_r(Tygh::$app['session']['auth']);

Use
fn_set_notification('W','Description', var_export($varialble,true) );
this gives a notificcation after the hook fires and I found it very useful for my dev purposes.
The W can also be I and E for information and Error. Basically all it does is change the style of the popup

Related

Cucumber test for AJAX call testing data has been saved

I have a web page which makes an AJAX call to update data in the database. I want to write a cucumber test to enter the data on the page, triggering the AJAX call, and then verify that the data was saved in the database.
When I fill in selectized with "BP"
And I enter selectized
And Bug "222222" should have tag "BP"
However, because AJAX is asynchronous, cucumber is testing that the bug has a tag before the controller has finished creating the data.
How can I have the test wait until the AJAX call is completed?
You can wait for an AJAX using selenium JavascriptExecutor
example:
public boolean isAjaxDone() {
JavascriptExecutor js = (JavascriptExecutor) driver;
Object result = js.executeScript("return document.readyState");
return result.equals("complete");
}
You need to check for whatever visual change on the page indicates the data has been saved/ajax has completed before checking the database. Sometimes that's a a text message
expect(page).to have_text('Bug Updated!')
sometimes it's a spinner disappearing
expect(page).not_to have_selector('.spinner')
etc. Something like that should probably be the last line of your I enter selectized step.
Note: This issue is one of the main reasons doing direct DB checks in feature tests is generally considered a bad code smell (makes sense in a request spec, etc), and you really should just be checking the information shown to the user.
You could poll for the expected result for a certain time and only fail if it hasn't gotten the expected result within that specified timeframe.

How to delete an item in expressJS view

I am building an ExpressJS app and want to add a delete icon on a collection to delete individual items.
I am a bit confused how to do this.
One method I thought of is binding a click event to the icon in the express view and doing an ajax call to the server when clicked.
Another method is to create a form around the icon and the icon will be a button that when clicked submits the form.
I am not confident of the two approaches, anybody have thought on an elegant way to do this the express way
i recommend the second method because it's more easy to understand at this moment.
from your words i understand the delete button could be vulnerability or security hole if you did in the wrong way. Sure it's delete button on any way.
the most easy way to do it with more secure is to use session variable.
the user can't delete unless he is authorized (logged in). if so then you open session on your server and give the user the key of that session.
In the session you can store securely data about the user who interact with the server via providing the session key you gave him at login process.
at this step the user will click the button to delete document but guess what he should be authorized to delete this document. This the time for session key he provide to you to inform you his identity. then the decision is up to you either to delete or reject his request.
all of the above word are concept of what will happen in the code.
i will write two part one part for the login controller to give the user authorization. And the second is the delete document controller.
login:
if(var user = isUser(username, password){
//open session
req.session.user_id = user._id
}
delete document controller:
if(req.session.user_id){
//if true that means he is logged in authorized user
//you can also to check by his user_id if he has the privilege to delete the document
document.delete();//in mongoose model.remove();
}
this solution is for security in deleting any document.
There are multiple ways you can achieve the result you seek.
You could use a link that has the id of the item you want to delete YourURL.com/item/delete/id and attach a click event to it. When the link is clicked your handler should be able to get the id query params and use it to make an AJAX call to the server.
Also, you can use a button like you said, which is basically the same thing as the one above
Bottom line is, both methods are pretty standard, some people could use hidden elements, HTML elements, almost anything that can store an ID or a value, but you will find that most people also use the above methods as well, Which IMHO is pretty standard.
Below is a snippet of how it should work, I am not sure if you are using any Javascript libraries so I scripted it with Vanilla Javascript, if you are not using any Javascript libraries or frameworks I strongly advice you do, it helps reduce a lot of headaches you get from browser difference in the way the handle Javascript.
PS: Include codes you have tried to help give context to how your question could be answered.
var makeDeleteCall = function(e, id) {
e.preventDefault();
console.log(id);
// Make AJAX Call here to server to delete item with the ID
//After call to remote server you can then update the DOM to remove the item
document.getElementById(id).remove();
}
<!-- Using Link -->
<a href="#/delete/1" onclick="makeDeleteCall(event, 1);" id="1">
Delete Item
</a>
<br/>
<br/>
<!-- Using a Button-->
<button onclick="makeDeleteCall(event, 2);" id="2">
Delete Button
</button>
Link to JSFiddle

XPages: execute context.redirectToPage after client side function?

Why does context.redirectToPage behave differently when executed in a view root-event instead of an event handler?
This question came up when I tried to set the language of an xpages application to the language saved in the user profile, once the user is logged in. I use a properties-file with translated strings in a resource bundle, and retrieve the strings like this:
<xp:text value="${langString['WELCOME_TEXT']}" />
When the language is changed and so a different properties-file is loaded, the page needs to be refreshed in order to update those strings. This worked fine when I added a full-refresh event handler to the login button, that executed a server side context.redirectToPage(). No luck with client side refreshes like location.reload or window.location.href=window.location.href (the login-function itself is a client side function though).
But of course the user expects that he is also logged in when he presses the enter key instead of the button after he has entered his credentials. So I added an onkeypress-event to the username and password input fields, and checked for the enter key (if (thisEvent.keyCode==13) dosomething...) before executing the login function.
But now the event handler is called every time a key is pressed and of course I do not want the context.redirectToPage to be executed all the time.
Thus I removed the server side event handlers and changed the login function so that it terminated with a partial refresh of the div containing the whole page:
var p = {"execLogin":"true"}; XSP.partialRefreshPost( '#{id:wholePage}', {params: p} );
The parameter sent via the partial refresh now triggers an event in which our context.redirectToPage is executed:
<xp:this.beforeRenderResponse><![CDATA[#{javascript:if (param.containsKey('execLogin') && param.get('execLogin').toString().equals('true')) {
print("test");
context.redirectToPage(context.getUrl().toSiteRelativeString(context),true);
}}]]></xp:this.beforeRenderResponse>
The page is refreshed and "test" is printed out, but I still see the old language strings. I have to refresh the page manually again to make the new user language take effect.
Any idea how to execute a genuine full refresh this way, or maybe another way to update the strings retrieved from the property bundle?
Thanks in advance. Regards,
Sarah
EDIT
I now have:
<xp:inputText id="cc_login_panel_login_username" styleClass="span2">
<xp:eventHandler event="onkeypress" submit="true" refreshMode="complete">
<xp:this.script><![CDATA[if (thisEvent.keyCode!=13) {
return false;
} else {
doLogin();
return true;
}]]></xp:this.script>
<xp:this.action><![CDATA[#{javascript:context.redirectToPage(context.getUrl().toSiteRelativeString(context));}]]></xp:this.action>
</xp:eventHandler>
Because context.reloadPage() didn't even log me in somehow (strange) I got back to using redirectToPage. The server side event is fired once and at the right time *thumbs up*, but the language properties-bevaviour is still the same.
$ is only set on page load, whereas # is set each time during the partial refresh.
I don't think a partial refresh will work at all though. This will refresh the computed field. However, it will need a full refresh to refresh the part of the XPage that includes the properties file. In other words, you would be refreshing the computed field, but using the same properties file.
I wonder if context.redirectToPage or context.reloadPage is somehow going to the same page but with the cached properties files.
If you're always wanting to come back to the same page, a full refresh instead of partial refresh may be the best option.
I think this has something to do with using the $ parameter. this tells the runtime to retrieve the language file the first time the current page is created in the back-end. When a user does a refresh it is actualy retrieving a saved version of the page you are viewing.
I see you're calling "context.redirectToPage(context.getURL().toSiteRelativeString(context)))" within an xp:this.action tag for the xp:eventHandler.
Try using xp:this.onComplete in place of xp:this.action.
According to the Designer tooltip for the action, the expected return is a string to be passed to the navigation handler. So instead giving the onComplete will execute the redirect command when it's done with the eventHandler group of events.
Thanks for all the helpful answers, in fact all of them did work, the problem turned out to be my misunderstanding of when the properties-file is loaded. It is loaded in an early phase, long before my new language is set to the sessionScope (that sessionScope variable is then used as a part of the name of the properties-file to be loaded, via the VariableResolver).
Now I use a double full refresh to load the new file. When the login function terminates successfully, it executes:
window.location.href = window.location.href + "?doRefresh=true";
And to the view root element I added the following event:
<xp:this.beforeRenderResponse><![CDATA[#{javascript:
if (context.getUrlParameter("doRefresh")!=null&&context.getUrlParameter("doRefresh").equals("true")) {
var url = context.getUrl().toSiteRelativeString(context);
url = url.replace("?doRefresh=true","");
context.redirectToPage(url);}
}]]></xp:this.beforeRenderResponse>
This is not a very sophisticated solution, but at least it works :-)

XPages sometimes refresh and lose content

I hope someone can help me solve a very serious problem we face at the moment with a business critical application losing data when a user works in it.
This happens randomly - I have never reproduced this but the users are in the system a lot more than me.
A document is created with a load of fields on it, and there are 2 rich text fields. We're using Domino 8.5.3 - there are no extension lib controls in use. The document has workflow built in, and all validation is done by a SSJS function called from the data query save event. There is an insane amount of logging to the sessionscope.log and also this is (now) captured for each user in a notes document so I can review what they are doing.
Sometimes, a user gets to a workflow step where they have to fill in a Rich Text field and make a choice in a dropdown field, then they submit the document with a workflow button. When the workflow button is pressed (does a Full Update) some client side JS runs first
// Process any autogenerated submit listeners
if( XSP._processListeners ){ // Not sure if this is valid in all versions of XPages
XSP._processListeners( XSP.querySubmitListeners, document.forms[0].id );
}
(I added this to try and prevent the RTF fields losing their values after reading a blog but so far it's not working)
then the Server-side event runs and calls view.save() to trigger QS code (for validation) and PS code to run the workflow agent on the server.
95% of the time, this works fine.
5% of the time however, the page refreshes all the changes made, both to the RFT field (CKEditor) and the dropdown field are reloaded as they were previously, with no content. It's like the save hasn't happened, and the Full Update button has decided to work like a page refresh instead of a submit.
Under normal circumstances, the log shows that when a workflow button is pressed, the QuerySave code starts and returns True. Then the ID of the workflow button pressed is logged (so I can see which ones are being used when I am reviewing problems), then the PostSave code starts and finally returns true.
When there is a problem, The QuerySave event runs, returns true if the validation has passed, or false if it's failed, and then it stops. The ID of the workflow button is also logged. But the code should continue by calling the PostSave function if the QuerySave returns true - it doesn't even log that it's starting the PostSave function.
And to make matters worse, after the failure to call the PostSave code, the next thing that is logged is the beforePageLoad event running and this apparently reloads the page, which hasn't got the recent edits on it, and so the users loses all the information they have typed!
This has to be the most annoying problem I've ever encountered with XPages as I can find no reason why a successful QuerySave (or even a failure because mandatory fields weren't filled in) would cause the page to refresh like this and lose the content. Please please can someone help point me in the right direction??
It sounds as if in the 5% use cases, the document open for > 30mins and the XSP session is timing out - the submit causes the component tree to be re-created, and the now empty page returned back to the user. Try increasing the time out for the application to see if the issue goes away.
I would design the flow slightly different. In JSF/XPages validation belongs into validators, not into a QuerySave event. Also I'd rather use a submit for the buttons, so you don't need to trigger a view.save() in code. This does not interfere with JSF's sequence of things - but that's style not necessarily source of your problem.... idea about that:
As Jeremy I would as a first stop suspect a timeout, then the next stop is a fatal issue in your QuerySave event, that derails the runtime (for whatever reason). You can try something like this:
var qsResult = false;
// your code goes here, no return statements
// please and if you are happy
qsResult = true;
return qsResult;
The pessimistic approach would eventually tell you if something is wrong. Also: if there is an abort and your querySave just returns, then you might run in this trap
function noReturn() {return; } //nothing comes back!
noReturn() == true; --> false
noReturn() == false; --> false
noReturn() != false; --> true!!!!
What you need to check: what is your performance setting: serialize to disk, keep in memory or keep latest in memory? It could be you running foul of the way JavaScript libraries work.
A SSJS library is loaded whenever it is needed. Variables inside are initialized. A library is unloaded when memory conditions require it and all related variables are discarded. so if you rely on any variable in a JS Function that sits inside a SSJS library between calls you might or might not get the value back, which could describe your error condition. Stuff you want to keep should go into a scope (viewScope seems right here).
To make it a little more trickier:
When you use closures and first class functions these functions have access to the variables from the parent function, unless the library had been unloaded. Also functions (you could park them in a scope too) don't serialize (open flaw) so you need to be careful when putting them into a scope.
If your stuff is really complex you might be better off with a backing bean.
Did that help?
To create a managed bean (or more) check Per's article. Your validator would sit in a application bean:
<faces-config>
<managed-bean>
<managed-bean-name>workflowvalidator</managed-bean-name>
<managed-bean-class>com.company.WfValidator</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>
</faces-config>
Inside you would use a map for the error messages
public Map<String,String> getErrorMessages() {
if (this.errorStrings == null) { // errorStrings implements the MAP interface
this.loadErrorDefinitions(); //Private method, loads from Domino
}
return this.errorStrings;
}
then you can use EL in the Error message string of your validators:
workflowvalidator.errorMessage("some-id");
this allows XPages to pick the right one directly in EL, which is faster than SSJS. You could then go and implement your own custom Java validator that talks to that bean (this would allow you bypass SSJS here). Other than the example I wouldn't put the notes code in it, but talk to your WfValidator class. To do that you need to get a handle to it in Java:
private WfValidator getValidatorBean() {
FacesContext fc = FacesContext.getCurrentInstance();
return (WfValidator) fc.getApplication()
.getVariableResolver()
.resolveVariable(fc, "workflowvalidator");
}
Using the resolver you get access to the loaded bean. Hope that helps!
My experience is that this problem is due to keeping page in memory. Sometimes for some reason the page gets wiped out of memory. I'm seeing this when there is a lot of partial refreshes with rather complex backend Java processing. This processing somehow seems to take the space from memory that is used by the XPage.
The problem might have been fixed in later releases but I'm seeing it at least in 8.5.2.
In your case I would figure out some other workaround for the CKEditor bug and use "Keep pages on disk" option. Or if you can upgrade to 9.0.1 it might fix both problems.

Getting data from the options page to the injected code

My extension runs on an existing web page I do not control. I want to have an options page for it. What I haven’t figured out is how to get the option values from the injected code. localStorage isn’t shared, of course. I’ve tried using sendRequest / addListener in both directions, although it would be much preferable to push values from the options page to the injected code than they other way ‘round.
At the beginning, I simply put the option checkboxes on the manipulated page (the one the code is injected into), and those checkboxes set values in localStorage:
localStorage.showStuff = !!$(evt.target).attr(‘checked’);
Then I check those values in the code:
if (localStorage.showStuff == ‘true’) { … }
I moved the checkbox code to the options page and had it do a sendRequest when the options changed, and had my injected code have a listener for the message, but it doesn’t get the messages (my background page does, but that doesn’t help me). I also tried having the injected code hand a callback to the options page, but the sendResponse object only seems to work for the duration of the notify handler (not surprising, but I had to give it a try).
Right now my manifest’s permissions lists the foreign page ("http://example.com/*") and “tab”.
The one thing I know I can do is asynchronously query the options page via a callback, but the code doesn’t (and really can’t) work asynchronously without serious rewriting.
Any and all ideas welcome, thanks in advance.
i'm new to chrome extensions but when i tried to write/read localstorage from both, background script and option page it worked perfectly.
i haven't tried native localstorage but chrome's storage api.
take a look at this
code A: (set)
chrome.storage.sync.set({'key':'qwe'});
code B: (get)
chrome.storage.sync.get('key', function(response) {
console.log(response); // 'qwe'
});
u could put either code A in the background and code B in the option page or the other way around.
they are using the same storage.
this works for me. i hope u'll get there too.
The thing to remember is that only the background page is long-lived. The rest of the pieces of your chrome extension are transient (content scripts for the duration of the site navigation, options pages only while open, etc).
So you have to use messaging and save things using the background page. However, get ready for the storage API which should be landing soon. This will make things a lot easier for you!
Check it out here.

Resources