How to get currentPagePath in Slingservlet? - aem

From some javascript I call the following Slingservlet with ("/bin/fooServlet?"+params);
#SlingServlet(paths = "/bin/fooServlet", methods = "GET", metatype = true)
public class FooServlet extends SlingAllMethodsServlet {
..
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {
Session session = resourceResolver.adaptTo(Session.class);
Page currentPage = pageManager.getPage(request.getPathInfo());
String currentPagePath = currentPage.getPath();
...
}
My Question is: How to get the currentPagePath of the current Page in FooServlet? currentPagePath in the code is null.

As Thomas mentioned, if you define a servlet with fixed paths property, you wouldn't have reference to a Resource.
One way of achieving this is by passing your page path along with the request to the servlet. Also CQ.WCM.getPagePath() returns only /libs/wcm/core/content/siteadmin, as the current page is siteadmin and you may need to tweak your script a bit in order to access the selected page within siteadmin.
To get your page path either from siteadmin or from the page itself, you can use the following script and then pass the value to your servlet for further processing.
var currentPagePath = null;
/* if accessed via siteadmin */
if(CQ.wcm.SiteAdmin.hasListSelection()) {
var grid = CQ.wcm.SiteAdmin.getActiveGrid();
var selections = grid.getSelectionModel().getSelections();
/*Assuming that you are selecting only one page at a time. */
currentPagePath = selections[0].id;
} else { /* accessed via page */
currentPagePath = CQ.WCM.getPagePath();
}
And then you can call the servlet with the currentPagePath as one of the parameters.
GET /bin/fooServlet?currentPagePath=' + currentPagePath + '&foo=bar';
UPDATE
The above code works fine for CQ 5.5 + , for older versions you can use this.
var currentPagePath = null;
/* if accessed via siteadmin */
if(CQ.wcm.SiteAdmin.hasListSelection()) {
var grid = CQ.Ext.getCmp(window.CQ_SiteAdmin_id + "-grid");
if (grid) {
var selections = grid.getSelectionModel().getSelections();
currentPagePath = selections[0].id;
}
} else { /* accessed via page */
currentPagePath = CQ.WCM.getPagePath();
}

If you define the servlet with a fixed paths property you don't have any reference to a Resource or Page
You either need to define resourceTypes that matches to a page component or use cq:Page, but this will then be active for every request to a page and is not recommended without at least some selectors
Then you can get the Resource with request.getResource(). To get a Page you'll need to adapt the ResourceResolver to a PageManager and use getContainingPage(Resource resource).
Have a look at the documentation:
http://sling.apache.org/documentation/the-sling-engine/servlets.html

request.getPathInfo() in this case presumably is /bin/fooServlet?[parameterString], which is why PageManager is returning null for its path — from the PageManager's point of view, no resource exists at this location.
One simple option would be to send an additional callingPage parameter when hitting the Servlet. This way you could just read it from the parameter map:
GET /bin/fooServlet?foo=bar&callingPage=/en/home.html
void doGet() {
PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
String callingPage = request.getParameter("callingPage");
String callingPagePath = pageManager.getPage(callingPage).getPath();
}

I don't know if it's a good pratice, but perhaps you could use the referer.
import java.net.URI;
import java.net.URISyntaxException;
try {
String currentPagePath = new URI(request.getHeader("referer")).getPath();
} catch (java.net.URISyntaxException e) {
}

Related

Form redirect for confirmation

Form redirect for confirmation can be currently managed using one of these two options:
1/ Flash message: using flashbag on the form page or another page like this:
$this->addFlash('success', 'Thank you');
return $this->redirectToRoute('confirmation_page');
2/ Confirmation page: using a dedicated confirmation like this:
return $this->redirectToRoute('confirmation_page');
BUT using option 2 makes the confirmation_page directly accessible from the browser without having submitted the form before. I am currently using flashbag mechanism to fix it by adding a $this->addFlash('success', true); before the redirection in the form and then checking the flashbag content in the confirmation page so that the route is accessible only once after being successfully redirected from the form.
Is there any best practice or more appropriate way to manage it?
/**
* #Route("/confirmation", methods="GET", name="confirmation_page")
*/
public function confirmation(): Response
{
$flashbag = $this->get('session')->getFlashBag();
$success = $flashbag->get("success");
if (!$success) {
return $this->redirectToRoute('app_home');
}
return $this->render('templates/confirmation.html.twig');
}
Flash Message is designed to display messages. Instead, use sessions in your application.
When submitting the confirmation form, create a variable in the session before the redirect
$this->requestStack->getSession()->set('verifyed',true);
return $this->redirectToRoute('confirmation_page');
Use the created variable in your method
public function confirmation(): Response
{
if (!$this->requestStack->getSession()->get('verifyed')) {
return $this->redirectToRoute('app_home');
}
return $this->render('templates/confirmation.html.twig');
}
Don't forget to inject the RequestStack into your controller
private RequestStack $requestStack;
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}

Callback function issues in FB.API for Unity

I am using Unity 5.5.2f1 pro and facebook's SDK v 7.9.4
I have a script which after login (managed in a previous scene) sends an API request to FB asking for friends, name and email and sends that info as a POST to a php website.
code:
[Serializable]
public struct FBData {
public string first_name;
public string email;
public string friends;
public string id;}
public class UserManagement : MonoBehaviour {
string urlSaveUserData="some php website";
public Text testTxt;
FBData parsedData;
// Use this for initialization
void Start () {
//Check if it's the first time the user is opening the app.
if (UserInfo.FIRST_TIME) {
//update text (only used for testing, should be removed in production.)
testTxt.text = "Your user id is: " + UserInfo.ID;
//Perform FB.API call to get User Data.
getUserData ();
//Save in SQL table. (won't get here if line in getUserData() is active)
StartCoroutine ("saveUserData");
} else {
//do something else.
}
note: Since this is meant for iOS I have to test it on a device so I'm using text in the screen to display info (think of it as a badly implemented print statement).
The problem: In my callback function for FB.API I write in the text Gameobject (aka testTxt) the parsed information from the response which is saved in the Custom UserInfo clss. It display's correctly but the code gets stuck there. It doesn't continue to the next function. HOWEVER, if I delete/comment that line and don't display anything in the text field. The codes does continue to the POST function BUT the information from the API call is not passed, i.e my custom class is empty (leading me to believe the callback function is not called at all).
public void getUserData(){
string query = "me?fields=first_name,email,friends";
FB.API (query, HttpMethod.GET, Apicallback, new Dictionary<string, string> ());
}
private void Apicallback(IGraphResult result){
//Parse Graph response into a specific class created for this result.
parsedData = JsonUtility.FromJson<FBData>(result.RawResult);
//Pass each field into UserInfo class.
UserInfo.EMAIL = parsedData.email;
UserInfo.FRIENDS = parsedData.friends;
UserInfo.NAME = parsedData.first_name;
UserInfo.FACEBOOKID = parsedData.id;
/*problem area, if I comment line below, then previous information is apparently not stored. If left as is then testTxt displays correct information but code gets stuck there. */
testTxt.text = "This is the info from USerInfoInside the APICallback: " + UserInfo.EMAIL + UserInfo.FRIENDS + UserInfo.FACEBOOKID;
}
The function below is to send info to php website, is there for illustrative purposes:
code:
public IEnumerator saveUserData() {
//get user info (this information is EMPTY if line in getUserData() is commented.
parsedData.id = UserInfo.FACEBOOKID;
parsedData.friends = UserInfo.FRIENDS;
parsedData.first_name = UserInfo.NAME;
parsedData.email = UserInfo.EMAIL;
//translate data into json
string JsonBodyData = JsonUtility.ToJson (parsedData);
//Custom web request (POST method doesnt seem to work very well, documentation example sends empty form)
var w = new UnityWebRequest(urlSaveUserData, "POST");
byte[] bodyRaw = new System.Text.UTF8Encoding().GetBytes(JsonBodyData);
w.uploadHandler = (UploadHandler) new UploadHandlerRaw(bodyRaw);
w.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer();
w.SetRequestHeader("Content-Type", "application/json");
yield return w.Send();
//work with received data...}
Im stuck here any help is appreciated. Thanks!
Be sure to use EscapeURL when using strings directly for JSON or HTTP POST and GET methods. The lack of this treatment tends to screw things over, particulary in iOS platforms.
From what I can see, this code
string query = "me?fields=first_name,email,friends";
should instead be escaped as
string query = WWW.EscapeURL("me?fields=first_name,email,friends");
so characters like "?" won't get encoded as an URL symbol.
I'm assuming you don't need to do that for your illustrative example, because UnityWebRequest already escapes your POST request strings internally, but I can't fully confirm that.

Play framework 2.1 HTTP HEAD method response

How can I return a only response header(HTTP HEAD method) on scala play framework 2.1?
Unfortunatelly there is Java solution but maybe you will 'convert' it to Scala, general concept is:
Catch HEAD request send it to dedicated method
The method autoHead(String originalPath) sends a GET request using WebServices forwarding params and returning only status of the response.
It adds additional header X_FORWARD_FROM_HEAD so if ie your action is logging something to the DB after each hit you can avoid that for HEAD requests.
code:
/**
* Tries to get headers of resource with WebServices and return headers only.
*
* #param originalPath Path of the resource
* #return Headers for HEAD request
* #throws IllegalAccessException
*/
public static Result autoHead(String originalPath) throws IllegalAccessException {
WS.WSRequestHolder forwardedRequest = WS.url("http://" + request().host() + request().path());
// this header will allow you to make additional choice i.e. avoid tracking the request or something else
// see condition in index() action
forwardedRequest.setHeader("X_FORWARD_FROM_HEAD", "true");
// Forward original headers
for (String header : request().headers().keySet()) {
forwardedRequest.setHeader(header, request().getHeader(header));
}
// Forward original queryString
for (String key : request().queryString().keySet()) {
for (String val : request().queryString().get(key)) {
forwardedRequest.setQueryParameter(key, val);
}
}
// Call the same path but with GET
WS.Response wsResponse = forwardedRequest.get().get();
// Set returned headers to the response
for (Field f : Http.HeaderNames.class.getFields()) {
String headerName = f.get(null).toString();
if (wsResponse.getHeader(headerName) != null) {
response().setHeader(headerName, wsResponse.getHeader(headerName));
}
}
return status(wsResponse.getStatus());
}
/**
* Checks if request if forwarded from HEAD request
*
* #return true if 'X_FORWARD_FROM_HEAD' header exists and is set to true
*/
public static boolean forwardedFromHead() {
return (request().getHeader("X_FORWARD_FROM_HEAD") != null && "true".equals(request().getHeader("X_FORWARD_FROM_HEAD")));
}
routes:
HEAD / controllers.Application.autoHead(originalPath:String ?= "/")
HEAD /*originalPath controllers.Application.autoHead(originalPath:String)
You can add a HEAD route, next to the GET route, like this:
GET /assertion controllers.Assertion.get
HEAD /assertion controllers.Assertion.head
In the implementing method, you can call the GET method and pass a flag to suppress the body, I guess.
What about returning EmptyContent as a content
Action {
....
Ok(EmptyContent())
}

Liferay Portlet and JSF : Redirect during Render Phase

I have a problem to implement a simple HTTP redirection.
I use Liferay 6.0.6, our portlets are build with JSF2.0 / PortletFaces.
I want to call a redirection when a view is loaded (and not when an action is triggered). Currently, my function is called by the PreRenderView listener.
<f:metadata>
<f:event listener="#{myControler.dispatch}" type="preRenderView" />
</f:metadata>
In this function, i can check the permissions, do other stuff, and in some cases I want to redirect the user to a new page (not another view).
I tried several methods, unsuccessfully.
Specifically, I thought that this method would work :
getFacesContext().getExternalContext().redirect(url);
getFacesContext().responseComplete()
// => Can only redirect during ACTION_PHASE
This error is logical, but is there a solution to force the redirection.
It could be realized in another function, called otherwise, I only need the Hibernate Session (set at the beginning of the Render Phase)
Have you ideas to resolve this problem?
Thanks!
ps : <redirect /> or ?faces-redirect don't work with the portlets.
You can't do this in the render phase by design. Reasons:
It's possible that portlets are rendered asynchronously, so the page might already be displayed when your portlet is being rendered
It's possible that parts of the page are already delivered to the client, so that the HTTP Headers are already sent - for this reason, by design you don't have access to them in the render phase
What would be the expected outcome if two portlets rendered on the same page would decide that they'd like to forwards to another page? Who would win?
A hacky workaround is to render some javascript redirect, but this is veeeery un-portal-like and can mess up other's expectations (plus, parts of the page might already be rendered, causing your users to fill a form only to be redirected by your javascript routine.
Please rethink the problem and come up with a different solution - it's really worth doing this in a portal environment.
I use this and it works for me:
public void preRenderView() throws IOException {
if (!checkUtente()) {
FacesContext fc = FacesContext.getCurrentInstance();
NavigationHandler navigationHandler = fc.getApplication().getNavigationHandler();
navigationHandler.handleNavigation(fc, null, "errore.xhtml?faces-redirect=true");
fc.renderResponse();
}
}
Use the below method it will work
public static void redirect(final String url) throws IOException {
final javax.portlet.PortletResponse portletResponse
= getPortletResponse();
if (portletResponse instanceof ActionResponse) {
final javax.portlet.ActionResponse actionResponse
= (javax.portlet.ActionResponse) portletResponse;
actionResponse.sendRedirect(url);
} else if (portletResponse instanceof ResourceResponse) {
final FacesContext ctx = FacesContext.getCurrentInstance();
if (ctx.getPartialViewContext().isPartialRequest()) {
final ResourceResponse portletResResp
= (ResourceResponse) portletResponse;
PartialResponseWriter pwriter;
final ResponseWriter writer = ctx.getResponseWriter();
if (writer instanceof PartialResponseWriter) {
pwriter = (PartialResponseWriter) writer;
} else {
pwriter = ctx.getPartialViewContext()
.getPartialResponseWriter();
}
portletResResp.setContentType(Constants.CONTENT_TYPE);
portletResResp.setCharacterEncoding(Constants.ENCODING_TYPE);
// addResponseHeader("Cache-Control", "no-cache");
pwriter.startDocument();
pwriter.redirect(url);
pwriter.endDocument();
ctx.responseComplete();
} else {
throw new UnsupportedEncodingException(
"Can only redirect during RESOURCE_PHASE "
+ "if a Partial-(JSF AJAX)-Request has "
+ "been triggered");
}
} else {
throw new UnsupportedEncodingException(
"Can not redirect during the current phase: "
+ portletResponse.getClass().getSimpleName());
}
}

multiple pages with C# Web browser control

I am trying to download HTML content from any URL through webbrowser control in C#.net.
I choose webrowser to handle Javascript issues. I am using webbrowser control without placing
it on the form. It works great for one url, but when I call it for multiple urls I am unable
to download the page.
Here is the code
GetWebpage()
{
System.Windows.Forms.WebBrowser wb = new System.Windows.Forms.WebBrowser();
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(wb_DocumentCompleted);
wb.Navigate(sURI, false);
bDocumentLoaded = false;
while (!bDocumentLoaded)
{
Application.DoEvents();
Thread.Sleep(100);
}
sHTML = wb.DocumentText;
bDocumentLoaded = false;
}
Event:
private void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
System.Windows.Forms.WebBrowser webBrowser1;
webBrowser1 = sender as WebBrowser;
string strTit = webBrowser1.DocumentTitle;
string str = webBrowser1.DocumentText;
bDocumentLoaded = true;
}
Cheers,
Karthik
You can use webclient object to fetch data from some url.
Try using Downloading String
public static void DownloadString (string address)
{
WebClient client = new WebClient ();
string reply = client.DownloadString (address);
Console.WriteLine (reply);
}
You can also use ASYC method of same downloading string.
I think your problem is that some sites are detecting specific browsertype and then they are returning HTML
Try setting the HeaderProperty of WebClient Object this is a list of HttpWebRequest Object
For Example
myWebClient.Headers.Add("Content-Type","application/x-www-form-urlencoded");
Modify the useragent of HTTPWEBRequest then add to headers.
HTTPWEBRequest.UserAgent=".NET Framework Test Client";
You can check more information about this in MSDN Link
I might recommend using the mshtml and SHDocVW libraries and using approach found in the answer here:
Unable to to locate and click a submit button using mshtml.HTMLInputElement