Is it possible to load a Liferay portlet dynamically on a page from a .jsp file? - liferay

I have a portlet that is deployed on a page and I need to produce a link that will load a different portlet (which is in a different module) in full-screen mode. I can load the built in Login portlet this way without a problem, but when I try to load any of my custom portlets I get two red error boxes with the message "You do not have the roles required to access this portlet." And I have the permissions - I can access the portlet fine when added to a page - and I'm even testing with an omni-admin account.
The portlet ID that has the .jsp file is 'subscriptionmanagement_WAR_subscriptionmanagementportlet' and the portlet ID I'm trying to load is 'GRPSignupForm_WAR_NY511RMportlet'. The tag is:
<liferay-portlet:renderURL portletName="GRPSignupForm_WAR_NY511RMportlet" var="grpPortlet" windowState="<%= WindowState.MAXIMIZED.toString() %>">
</liferay-portlet:renderURL>
Which produces the URL: http://localhost:8080/group/test/unsubscribe?p_p_id=tripitinerary_WAR_NY511RMportlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view
However, as I've mentioned, I have been able to load other portlets in this way. The login portlet for example using the same tag works fine:
<liferay-portlet:renderURL portletName="<%= PortletKeys.LOGIN %>" var="loginURL" windowState="<%= WindowState.MAXIMIZED.toString() %>">
<portlet:param name="mvcRenderCommandName" value="/login/login" />
</liferay-portlet:renderURL>
The obvious difference is that it is passing a specific render command parameter, but otherwise it is the same. It produces the URL:
http://localhost:8080/group/test-1/unsubscribe?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view&_com_liferay_login_web_portlet_LoginPortlet_mvcRenderCommandName=%2Flogin%2Flogin
For completeness, here is the code for the portlet I'm trying to load. But as I mentioned above, I have tried to load various portlets in this project and all of them produce the permissions error.
#Component(
immediate = true,
property = {
"com.liferay.portlet.display-category=root//NYSDOT//GRP",
"com.liferay.portlet.instanceable=false",
"com.liferay.portlet.header-portlet-css=/css/main.css",
"com.liferay.portlet.footer-portlet-javascript=/js/main.js",
"com.liferay.portlet.css-class-wrapper=grh-signup-form-portlet",
"javax.portlet.display-name=GRP Signup Form",
"javax.portlet.init-param.template-path=/html/",
"javax.portlet.init-param.add-process-action-success-action=false",
"javax.portlet.init-param.config-template=/html/configuration.jsp",
"javax.portlet.init-param.view-template=/html/view.jsp",
"javax.portlet.init-param.edit-template=/html/edit.jsp",
"javax.portlet.name=" + GRPSignupPortletKeys.GRPSIGNUP,
"javax.portlet.resource-bundle=content.Language",
"javax.portlet.security-role-ref=administrator,guest,power-user,user"
},
service = Portlet.class
)
public class GRPSignupPortlet extends GenericPortlet {
...
...
}
So it's obviously possible, as the Login portlet works. I'm sure there is just some small bit of config I'm missing. I've tried to see what is different in the Liferay Login portlet that allows it to work, but haven't found the secret.
Liferay CE 7.3

You need to add the property 'add-default-resource'. In the component add:
"com.liferay.portlet.add-default-resource=true"
From portal.properties: "add-default-resource" set to true will allow those portlets to be dynamically added to any page by any user. This is useful (and necessary) for some portlets that need to be dynamically added to a page, but it can also pose a security risk because it also allows any user to do it.
It's prudent to also add
"com.liferay.portlet.add-default-resource-check-enabled=true",
From portal.properties: Set this property to true to add a security check around this behavior. If set to true, then portlets can only be dynamically added to a page if it contains a proper security token. This security token is automatically passed when using a portlet URL from one portlet to another portlet.

Related

How to retrieve data from portlet to portal_normal.flt - Liferay

I want to retrieve some data from my custom portlet and put it to meta tags in portal_normal.ftl .
I've tried this:
<#if (renderRequest.getAttribute("something"))??>
<#assign urlImg = renderRequest.getAttribute("something")/>
<#else>
<#assign urlImg = "defaultturl"/>
</#if>
, but i always get null. Probably my portlet is loaded after theme and it will never acces this data.
Have you any idea how to solve it?
Thanks!
It is not common that a custom Portlet will provide data for the theme. Also, I am not sure if it will be the same Request object in the theme as in your Portlet, because some request related objects (session etc.) are usually scope to the Portlet (unshared).
You should rather use a Theme Context Contributor as descripted on this Liferay tutorial: DXP context-contributors. When using TYPE_THEME and implementing the interface, you can add data to your theme template.

How to dynamically authorize users in MVC inside Application_Start

I am using MVC 5 to build an application. In my web.config I have defined a custom section which I will use to display menu to user. It is something like:
<Menus>
<Menu>
<MainMenu Title="Home"></MainMenu>
<SubMenus>
<SubMenu Title="Page1" PageName="home/index" ADGroup="BusinessUsers">
<SubMenu Title="Page2" PageName="home/index2" ADGroup="ITUsers">
</SubMenus>
</Menu>
<Menu>
<MainMenu Title="About Us"></MainMenu>
<SubMenus>
<SubMenu Title="Another Page1" PageName="about/mypage1" ADGroup="BusinessUsers">
<SubMenu Title="Some Other Page" PageName="about/mypage2" ADGroup="OtherUsers">
</SubMenus>
</Menu>
</Menus>
I am using Windows authentication and everyone will have access via AD groups. By default I have denied access to all users using authorization rule in web.config like below:
<authorization><deny users="*"/></authorization>
Is it possible to define authorization rules based on MENU above in Application_Start at runtime? Something like:
Global.Filters.AuthorizeUser("BusinessUsers", "home/index, about/mypage1");
Global.Filters.AuthorizeUser("ITUsers", "home/index2");
What you're doing here isn't a standard way of defining a menu, so there is no standard way of enforcing authorization on it. You will need to implement it yourself.
Somewhere in your code during a request, you will have to loop through each SubMenu and use HttpContext.Current.User.IsInRole("DOMAIN\\GroupName") to test whether the user is in the appropriate group. I can't give you any further direction than that without seeing more of your code.
I'm sure you have your reasons for putting this in web.config, but what I have done in my own projects is define the menu in a partial view and check the roles right in the view:
#if (HttpContext.Current.User.IsInRole("DOMAIN\\GroupName") {
Some menu item
}
If you're worried about being able to update the menu items without recompiling the whole project, then that's still fine since the cshtml files aren't compiled anyway - you can update it on the fly.

Liferay - Theme - Questions about get configurable settings via themeDisplay.getTheme().getSetting() in spring mvc controller

This is my question:
I use the following way to add configurable settings to my theme.
<setting key="theme-mode" configurable="true" value="default"></setting>
and then use theme.getSetting("theme-mode") in my freemarker theme to get the value ,it is working well.
Now I want to get the configurable value in my spring mvc controller:
ThemeDisplay themeDisplay=(ThemeDisplay)request.getAttribute(WebKeys.THEME_DISPLAY);
String themeMode = themeDisplay.getTheme().getSetting("theme-mode");
but themeMode got default ,I already change it in the edit page ,and theme.getSetting("theme-mode") in theme is work well.
do you know why ,please tell me.
Thank you for your help!
Try this:
ThemeDisplay td = (ThemeDisplay)renderRequest.getAttribute(WebKeys.THEME_DISPLAY);
System.out.println(td.getThemeSetting("theme-mode"));
I've tried this on my portlet and it's working

Portlet preferences scope in a Liferay configuration page

I develop a Liferay portlet which has preferences unique per layout: preferences are specific to each portlet window, and users can modify them through "Preferences" option (Edit mode).
In liferay-portlet.xml:
<preferences-unique-per-layout>true</preferences-unique-per-layout>
However i would like to add a configuration page, in order to manage global parameters which should be shared across all portlet windows. Currently these parameters are handled as "init-param" in portlet.xml but it is not very convenient, admin users should be able to change those parameters through portal UI.
I followed the approach described here to create a such page, it works for the current portlet window but preferences are not shared. Is it possible to use a specific scope for some preferences? This other wiki makes use of a method specifying "uniquePerLayout" and "uniquePerGroup" but i did not find this method in APIs from 5.2.3 to 6.2
public static PortletPreferences getPortletSetup(
ActionRequest req,
String portletId,
boolean uniquePerLayout,
boolean uniquePerGroup)
Please could someone enlighten me on this subject?
Thanks!
In 6.2, There is getPortletSetup method that accept layout and group,
PortletPreferencesFactoryUtil.getPortletSetup(scopeGroupId, layout,
portletId, defaultPreferences).
You can get scopeGroupId, layout from themeDisplay as below and portletId & defaultPreferences should be set as per your requirement.
ThemeDisplay themeDisplay = (ThemeDisplay) actionRequest.getAttribute(WebKeys.THEME_DISPLAY);
Layout layout = LayoutLocalServiceUtil.getLayout(themeDisplay.getPlid());

Why to use PortletURL?

This thread is not a question , it was a doubt raised when I was going through Liferay Forums about using PortletURL.
In some cases I see this PortletURL inside the javscript Method
function createRowURL() {
var portletURL = new Liferay.PortletURL();
portletURL.setParameter("rowNumber", "25" );
return portletURL.toString();
}
In some cases I see this PortletURL inside the doView Method as shown
To get currentURL :
PortletURL url = PortletURLUtil.getCurrent(renderRequest, mimeResponse or renderResponse)
creating PortletURL from renderResponse :
For RenderURL:
PortletURL renderURL = renderResponse.createRenderURL();
For actionURL:
PortletURL actionURL = renderResponse.createActionURL();
Could anybody please tell me in which case PortletURL would be useful ?
Portlet applications are different from normal web applications. Portlets are mini pages inside a parent page called a portal and multiple portals become a book (a Weblogic term). Normal URL will not work in this situation. Aside from the reason given above, a portlet has a life circle with different states. You have to give the Portlet container a way to determine which portlet is communicating with it and what state it is being in - such as the window state of the portlet - is it minimized, maximized, or normal. Of course, another important function of the PortletUrl is to carry request parameters. If you are looking at a PortletURL you will sure see a lot exotic names along with the request parameters you give it.
Although most of the information needed by a PortletURL are common in many situations, the structure of a PortletURL is implementation-dependent and it is generated by the Portlet container one way or the other. There has been some time since my last liferay experience. I never used liferay specific javascript in my application. I used my own javascript/ajax to communication with the portal container. So I am just guessing the javascript way you presented is also liferay specific and won't be portable among different portal frameworks.
Edit: added types of PortletURLs and their differences and usage following comment from #PrakashK.
There are two types of PortletURLs:
Action URLs, they trigger an action request followed by a render request.
Render URLs, they trigger a render request.
So the purpose of an ActionURL is to trigger some kind of action - such as pressing a button. The action request will be intercepted by portlet container and send to appropriate action request handlers which process the action request and set necessary render parameters to be used by the render phase. In the life cycle of a portlet, a render request ALWAYS follows an action request. On the other hand, a RenderURl, as it's name suggested, is mainly for rendering the portlet.
Because of the "rendering" nature of a RenderURL, in JSR168(Portlet 1.0), you could not serve dynamically generated resources directly through the portlet. The only workaround is to use an additional servlet to serve the resources. The biggest problem of this approach is the inability of a Servlet to be involved in the lifecycle of a portlet. Direct links to the resources in the same portlet web application are not guaranteed to pass through the portal server and will not have portlet context available. To overcome this, in JSR286(Portlet 2.0), a feature called resource serving and a new kind of URL called ResourceURL has been introduced to enable a portlet to dynamically serve a resource. ResourceURL is not a PortletURL although they extend the same BaseURL. The biggest difference between a ResourceURL and an ActionURL is that a ResourceURL will NOT trigger a render request. This makes possible an Ajax request to the resource.
For more information on Portlet 2.0, please refer to [JSR286].
Hope the above information would be useful to you.

Resources